F#正则表达式
此词法分析器允许您使用F#计算表达式以非常声明的方式定义基于正则表达式的规则。
打开 Lexer
让 定义=
lexerDefinitions {
做!addNextlineDefinition “NEWLINE” @ “(\ n \ r)| \ n | \ r”“
做!addIgnoreDefinition “WS” @ “\ s”
做!addDefinition “让” “让”
做!addDefinition “ID” “(?i)[az] [a-z0-9] *”
做!addDefinition “FLOAT” @ “[0-9] + \。[0-9] +”
做!addDefinition “INT” “[0-9] +”
做!addDefinition “OPERATOR” @ “[+ * =!/&| <> \ ^ \ - ] +”
}
通过这些定义,您可以执行词法分析器:
打开 Lexer
让 lex输入=
试试
让 y = Lexer.tokenize定义输入
printfn “%A” y
与 e - > printf “%s” e.Message
lex “让a = 5”
这将导致:
seq [
{name = “LET” ; text = “let” ; pos = 0 ; column = 0 ; line = 0 ;};
{name = “ID” ; text = “a” ; pos = 4 ; column = 4 ; line = 0 ;};
{name = “OPERATOR” ; text = “=” ; pos = 6 ;列= 6 ; line = 0 ;};
{name = “INT” ; text = “5” ; pos = 8 ; column = 8 ; line = 0 ;}]
词法分析器的代码分为三个部分。第一部分是使用F#计算表达式的状态monad。这使得声明性方法(见上文)能够设置词法分析器规则。
模块 StateMonad
类型 State <'s,'a> = State of ('s - >('a *'s))
let runState(State f)= f
type StateBuilder()=
member b.Return(x)= State(fun s - >(x,s))
member b.Delay(f)= f():State <'s,'a>
member b.Zero()= State(fun s - >((),s))
成员 b.Bind(状态p,休息)=状态(有趣的 s - > 让 v,s2 = p s in (runState(rest v))s2)
成员 b.Get()=状态(有趣 的 - >(s,s) ))
成员 b.Put s = State(fun _ - >((),s))
第二部分是用于定义词法分析器规则的组合器。有三个主要组合器: AddDefinition允许您定义名称/正则表达式对, AddIgnoreDefinition允许您定义词法分析器应忽略的字符, AddNextlineDefinition允许您定义哪些字符确定新行。
输入 LexDefinitions =
{regexes:string list;
名称:字符串列表;
nextlines:布尔列表;
忽略:布尔列表; }
让 buildDefinition命名模式nextLine ignore =
州{
让!x = state.Get()
做!state.Put {regexes = x.regexes @ [sprintf @ “(?<%s>%s)” name pattern];
names = x.names @ [name];
nextlines = x.nextlines @ [nextLine];
ignores = x.ignores @ [ignore]}
}
让 addDefinition名模式= buildDefinition名字模式 假 虚假
让利 addIgnoreDefinition名模式= buildDefinition名字模式 假 真
让 addNextlineDefinition名模式= buildDefinition名称模式 真 真实
最后一部分是执行标记化的代码。它使用Seq.unfold方法创建令牌列表。Unfold是一个函数,它接受一个项目并从中生成一个新项目列表。它与Seq.fold相反,它接受一个项目列表并将其转换为单个项目。tokenize函数使用Seq.unfold生成每个标记,同时跟踪当前行号,该行中的位置以及输入字符串中的位置。
类型 Token =
{name:string;
text:string;
pos:int;
column:int;
line:int}
让 createLexDefs pb =(runState pb){regexes = []; names = []; nextlines = []; ignores = []} |> snd
let tokenize lexerBuilder(str:string)=
let patterns = createLexDefs lexerBuilder
let combinedRegex = Regex(List.fold(fun acc reg - > acc + “|” + reg)(List.head patterns。 regexes)(List.tail patterns.regexes))
让 nextlineMap = List.zip patterns.names patterns.nextlines |> Map.ofList
let ignoreMap = List.zip patterns.names patterns.ignores |> Map.ofList
let tokenizeStep(pos, line,lineStart)=
if pos> = str.Length then
没有
否则
让 getMatchedGroupName(grps:GroupCollection)names = List.find(fun (name:string) - > grps。[name] .Length> 0)名称
匹配 combinedRegex.Match(str,pos) with
| 公吨 时 mt.Success && POS = mt.Index - >
让 组名= getMatchedGroupName mt.Groups patterns.names
让 柱= mt.Index - lineStart
让 nextPos = POS + mt.Length
让 (nextLine,nextLineStart)= 如果 nextlineMap.Item groupName 然后 (行+ 1,nextPos) else (line,lineStart)
let token = if ignoreMap.Item groupName
then None
else Some {
name = groupName;
text = mt.Value;
post = post;
line = line;
column = column; }
一些(令牌,(nextPos,nextLine,nextLineStart))
| 否则 - >
let textAroundError = str.Substring(pos,min(pos + 5)str.Length)
raise(ArgumentException(sprintf “Lexing error in line:%d and column:%d near text:%s” line(pos - lineStart)textAroundError))
Seq.unfold tokenizeStep(0, 0, 0)|> Seq.filter(有趣 X - > x.IsSome)|> Seq.map(有趣 X - > x.Value)
最后,这是使用XUnit.Net编写的单元测试:
模块 LexerFacts
开放 的xUnit
开放 词法
开放 System.Linq的
让 simpleDefs =
州{
做!addNextlineDefinition “NextLine” “/”
做!addIgnoreDefinition “IgnoredSymbol” “= +”
做!addDefinition “String” “[a-zA-Z] +”
做!addDefinition “Number” “\ d +”
做!addDefinition “名称” “马特”
}
[<事实>]
让 Will_return_no_tokens_for_empty_string()=
让 令牌= Lexer.tokenize simpleDefs “”
Assert.Equal(0,tokens.Count())
[<事实>]
让 Will_throw_exception_for_invalid_token()=
让 代币= Lexer.tokenize simpleDefs “ - ”
让 EX = Assert.ThrowsDelegateWithReturn(乐趣 () - > 向上转型 tokens.Count())|> Record.Exception
Assert.NotNull(前)
Assert.True(例如:?System.ArgumentException)
[<事实>]
让 Will_ignore_symbols_defined_as_ignore_symbols()=
让 令牌= Lexer.tokenize simpleDefs “=========”
Assert.Equal(0,tokens.Count())
[<事实>]
let Will_get_token_with_correct_position_and_type()=
let tokens = Lexer.tokenize simpleDefs “1one = 2 = two”
Assert.Equal(“Number”,tokens.ElementAt(2).name)
Assert.Equal(“2”,tokens.ElementAt(2).text)
Assert.Equal(5,tokens.ElementAt(2).pos)
Assert.Equal(5,tokens.ElementAt(2).column)
Assert.Equal(0,tokens.ElementAt(2).line)
[<事实>]
let Will_tokenize_string_with_alernating_numbers_and_strings()=
let tokens = Lexer.tokenize simpleDefs “1one2two”
Assert.Equal(“1”,tokens.ElementAt(0).text)
Assert.Equal(“one”,tokens.ElementAt(1).text)
Assert.Equal(“2”,tokens.ElementAt(2).text)
Assert.Equal(“two”,tokens.ElementAt(3).text)
[<事实>]
let Will_increment_line_with_newline_symbol()=
let tokens = Lexer.tokenize simpleDefs “1one /
2two ” Assert.Equal(“Number”,tokens.ElementAt(2).name)
Assert.Equal(“2”,tokens.ElementAt(2).text)
Assert.Equal(5,tokens.ElementAt(2).pos)
Assert.Equal(0,tokens.ElementAt(2).column)
Assert.Equal(1,tokens.ElementAt(2).line)
[<事实>]
let Will_give_priority_to_lexer_definitions_defined_earlier()=
let tokens = Lexer.tokenize simpleDefs “Matt”
Assert.Equal(“String”,tokens.ElementAt(0).name)
F#正则表达式的更多相关文章
- Codeforce727B --- Bill Total Value(字符串处理 正则表达式)
先说一下正则表达式 %*[a-z]表示忽略前面的小写字符,%[0-9]表示把紧接着非字符的连续数字存入t字符串中去; 从"abc123de4f"中得到"123" ...
- JQuery中trim函数的具体实现代码
由于Javascript 1.8.1 之前的版本,没有内置 trim 函数,所以 JQuery 对它有自己的实现.不同的JQuery版本,trim函数的实现也不尽相同. 阅读本文需要掌握正则表达式用法 ...
- vimer
vimer 第1.0章.统一概念 不管学什么技术,我都深信概念是最重要的.是影响整个学习轨迹,决定能在这个技术领域高度. 当然如果你现在的目的不是在学习而在于解决问题(很多人不愿意承认,或者没发现 ...
- WinMerge 过滤器用法
WinMerge是一款开源的文件对比合并工具.http://winmerge.org/WinMerge提供了“过滤器”功能,可以在对比时排除特定的目录或文件. 1.编辑过滤规则工具 -> 过滤器 ...
- 菜鸟vimer成长记——第1章、统一概念
不管学什么技术,我都深信概念是最重要的.是影响整个学习轨迹,决定能在这个技术领域高度. 当然如果你现在的目的不是在学习而在于解决问题(很多人不愿意承认,或者没发现),那概念就暂时没那么重要了. 目的 ...
- pkill命令详解
基础命令学习目录首页 原文链接:http://www.mamicode.com/info-detail-2315063.html 一:含义: 是ps命令和kill命令的结合,按照进程名来杀死指定进程, ...
- pkill详解
pkill详解 一:含义: 是ps命令和kill命令的结合,按照进程名来杀死指定进程,pkill和killall应用方法差不多,也是直接杀死运行中的程序:如果您想杀掉单个进程,请用kill来杀掉. 二 ...
- mongodb增删改查操作
Note:mongodb存储的是文档,且文档是json格式的对象,所以增删改查都必须是json格式对象. 注:mongodb常用库和表操作,但mongodb在插入数据时,不需要先创建表. show d ...
- Mysql_以案例为基准之查询
查询数据操作
- F#之旅9 - 正则表达式
今天,cozy群有个群友发了条正则,问正则匹配相关的问题.虽然他的问题用html selector去处理可能更好,但是我也再一次发现:我忘了正则怎么写的了! 忘掉正则是有原因的,这篇文章会简单记录下F ...
随机推荐
- 数据库历险记(一) | MySQL这么好,为什么还有人用Oracle?
关系型数据库(Relational DataBase Management System),简称 RDBMS.说起关系型数据库,我们脑海中会立即浮现出 Oracle.MySQL.SQLServer 等 ...
- java8中stream的map和flatmap的理解
转自https://blog.csdn.net/wynjauu/article/details/78741093 假如我们有这样一个需求给定单词列表["Hello","W ...
- procotol.go 源码阅读
) return } bufferOver = buffer[i:] return } //整形转换成字节 // func IntToBytes(n int) ...
- BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表
BZOJ_2006_[NOI2010]超级钢琴_贪心+堆+ST表 Description 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的 音乐 ...
- cocoapods安装及使用其中 添加新源: gem sources -a https://ruby.taobao.org/
一.概要 iOS开发时,项目中会引用许多第三方库,CocoaPods(https://github.com/CocoaPods/CocoaPods)可以用来方便的统一管理这些第三方库. 二.安装 由于 ...
- golang 中 string 转换 []byte 的一道笔试题
背景 去面试的时候遇到一道和 string 相关的题目,记录一下用到的知识点.题目如下: s:="123" ps:=&s b:=[]byte(s) pb:=&b s ...
- i春秋------Misc更新
今天早上起来很开森!因为今天要打比赛了(2018年3月安恒杯线上赛),等到比赛开始得时候,发现自己登陆不上去 想了很久发现自己只是预约了比赛,并没有报名(QAQ ),心疼一下傻傻的自己.现在开始工作: ...
- GraphQL 入门介绍
写在前面 GraphQL是一种新的API标准,它提供了一种更高效.强大和灵活的数据提供方式.它是由Facebook开发和开源,目前由来自世界各地的大公司和个人维护.GraphQL本质上是一种基于api ...
- Go中原始套接字的深度实践
1. 介绍 2. 传输层socket 2.1 ICMP 2.2 TCP 2.3 传输层协议 3. 网络层socket 3.1 使用Go库 3.2 系统调用 3.3 网络层协议 4. 总结 4.1 参考 ...
- 滴滴 App 的质量优化框架 Booster,开源了!
一. 序 当 App 达到一定体量的时候,肯定是要考虑质量优化.有些小问题,看似只有 0.01% 触发率,但是如果发生在 DAU 过千万的产品中,就很严重了. 滴滴这个独角兽的 DAU 早已过千万,自 ...