这几天比较忙,让大家久等了。但是我语法分析篇还需要一些准备,所以今天带来一个特别娱乐项目。其实也正好想多举一些例子,介绍VBF.Compilers.Scanner库的使用方法。今天的问题来自于一道腾讯的PHP面试题,原题如下:
原 题是要求使用PHP的,我们只是娱乐,不是真面试,当然就无视各种规定了。这道题不必使用词法分析的原理,可以写出很快的算法。但是用词法分析库来实现也 是个不错的注意,因为DFA词法分析是O(N)的算法而且实际执行起来效率相当不错。下面我们就用VBF.Compilers.Scanner库来解决这 道题:
Imports VBF.Compilers.Scanners
Imports VBF.Compilers.Scanners.RegularExpression
Imports System.IO发型烫染技巧与技术
Module Program
Sub Main(args As String())
Dim findword = args(0)
Dim bibleLexicon As New Lexicon()
Dim lex = bibleLexicon.DefaultLexer
'定义要寻找单词的词法
Dim TARGET = lex.DefineToken(Literal(findword))
'定义一般单词的词法
Dim WORD = lex.DefineToken((Range("0"c, "9"c) Or
Range("a"c, "z"c) Or
Range("A"c, "Z"c)).Many1)
'定义换行
Dim LF = lex.DefineToken(Symbol(vbLf) Or Literal(vbCrLf))
'定义其他所有符号均忽略
Dim OTHER = lex.DefineToken(Range(ChrW(0), ChrW(255)))
Dim bibleScanner As New PeekableScanner(bibleLexicon.CreateScannerInfo())
bibleScanner.SetSkipTokens(OTHER.Index)
Using sr As New StreamReader("bible.txt")
Dim source As New SourceReader(sr)
bibleScanner.SetSource(source)
Dim scannerWatch As New Stopwatch
Dim lines = 1, columns = 1, totalwords = 0, targetwords = 0
scannerWatch.Start()
Do While bibleScanner.Peek() <> bibleScanner.ScannerInfo.EndOfStreamTokenIndex
Dim x As Lexeme = bibleScanner.Read()
Select Case x.TokenIndex
Case TARGET.Index
Console.WriteLine("第{0}行,第{1}列", lines, columns, x.Value)
columns += 1
targetwords += 1
totalwords += 1
Case WORD.Index
columns += 1
totalwords += 1
Case LF.Index
lines += 1
columns = 1
End Select
Loop
scannerWatch.Stop()
Console.WriteLine("总单词数: " & totalwords)
Console.WriteLine("目标单词出现次数: " & targetwords)
Console.WriteLine("消耗时间: " & scannerWatch.ElapsedMilliseconds)
End Using
End Sub
End Module
这就是完整的代码。为了统计是第几个单词,我们按照题目的规定,定义了一般单词的词法,目标单词的词法,并且忽略所有其他字符(设定为SkipTokens)。分析过程就是不断读取下一个单词,直到文件的末尾。注意,这次我展示的是具有超前查看功能的PeekableScanner 类,它可以超前查看任意多个单词,其实也可以用普通的Scanner而且性能更好。现在大家可以试试圣经中出现了什么单词,比如我们试一下apple:android 实现定时器
第5769行,第29列 第14112行,第8列 第16578行,第14列 第17558行,第8列 第17646行,第25列 第20351行,第34列 第22304行,第23列 第22908行,第31列 |
可见我手里这本圣经出现了8次apple(我特意看了前面,亚当和夏娃吃的是fruit,不是apple……)。如果搜microsoft的话发现圣经中并没有出现,怪不得苹果最近这么风光……