替换-megaarsec
替换-megaarsec用于查找文本模式,而且替换或拆分找到的模式。此活动传统上是使用正则表达式完成的,但是替换-megaarsec使用百万帕斯卡用于模式匹配的解析器。
替换-megaarsec可以用于相同类型的“模式捕获”或使用Python的“查找所有”情况雷·芬达尔
或波尔米//
,或Unix公司格雷普
.
替换-megaarsec可用于相同类型的“流编辑”或使用Python的“搜索和替换”情况re.sub公司
,或波尔秒///
,或Unix塞德
,或awk公司
.
替换-megaarsec可用于相同类型的“字符串拆分”使用Python的情况重新拆分
或Perl分裂
.
请参见替换-解析对于阿托帕塞克版本。
为什么我们要用解析器而不是正则表达式来进行模式匹配和替换?
-
Haskell解析器的语法比正则表达式,这是出了名的难以阅读.
-
正则表达式可以对匹配的模式,但它们只能返回捕获组的字符串列表。分析器可以基于捕获组构造类型化数据结构,确保模式规则和我们使用的规则之间没有分歧根据模式匹配构建数据结构。
例如,考虑扫描字符串中的数字。很多不同的东西看起来像一个数字,可以有前导加号或减号,也可以用科学符号表示,或者有逗号之类的。如果我们试图从字符串中解析所有数字使用正则表达式,则必须确保正则表达式字符串到数字的转换函数与以及什么不是数字字符串。我们可能会陷入尴尬的境地正则表达式表示它找到了一个数字字符串,但字符串到数字的转换功能失败。类型化解析器将执行这两项操作模式匹配和转换,因此永远不会出现这种情况。解析,而不是验证。
-
正则表达式只能进行模式匹配有规律的语法。Megaparsec解析器能够进行模式匹配的上下文无关语法,以及如果需要,甚至可以使用上下文敏感语法。参见下文提升a的示例分析器
到州
上下文敏感的monad模式匹配。
-
基于传统正则表达式的替换表达式替换命令通常只是一个字符串模板,其中这个第N个可以使用语法插入“捕获组”\N个
。使用这个库,而不是模板,我们得到一个编辑
可以执行任何计算(包括IO)的函数。
使用示例
示例取决于这些导入。
导入数据。无效导入替换。百万帕斯卡导入文本。百万帕斯卡导入文本。Megaparsec公司。烧焦导入文本。Megaparsec公司。烧焦。莱克瑟
使用拆分字符串拆分Cap
查找所有模式匹配项,捕获匹配的文本和解析的结果
将输入字符串分隔成可以解析为十六进制的部分带前缀的数字“0x”
,和不能的部分。分析数字。
让hexparser=chunk“0x”*>十六进制::Parsec无效字符串整数splitCap(匹配十六进制分析器)“0xA 000 0xFFFF”
[右(“0xA”,10),左“000”,右(“xFFFF”,65535)]
查找所有模式匹配项,仅捕获匹配模式的位置
找到流中所有的字母部分。捕获的列表每个模式匹配开始的偏移量。
导入数据。要么let letterOffset=getOffset<*some letterChar::Parsec无效字符串Intrights$splitCap letterOffset“a bc”
[1,4]
模式匹配平衡括号
查找平衡嵌套括号组。这是一个示例“上下文无关”语法,一种不能用正则表达式表示的模式表达式。我们可以用递归解析器表示模式。
导入数据。Functor(无效)导入数据。双函子(秒)let parens::Parsec无效字符串()parens=做字符“(”直到(void(noneOf“()”)<|>无效parens)(字符')')纯()第二个fst<$>splitCap(匹配参数)“(())(()())”
[右“()”、左“”、右“(()())”]
使用编辑字符串stream编辑
以下示例显示了如何搜索文本字符串中的模式然后编辑文本字符串以替换某些替换文本用于匹配的模式。
模式匹配并替换为常量
用换行符替换所有车厢换行符。
let crnl=chunk“\r\n”::Parsec无效字符串streamEdit crnl(const“\n”)“1\r\n2\r\n”
“1\n2\n”
模式匹配并编辑匹配项
将字母字符替换为字母表中的下一个字符。
let somelet=some letterChar::Parsec无效字符串流编辑somelet(fmap-suck)“HAL 9000”
“IBM 9000”
模式匹配,可能编辑匹配,也可能不去管它们
查找所有字符串部分秒
可以解析为十六进制数第页
,如果r≤16
,然后更换秒
带有十进制数。使用比赛
组合器。
让hexparser=chunk“0x”*>十六进制::Parsec无效字符串整数streamEdit(匹配十六进制分析器)(\(s,r)->如果r<=16,则显示r else s)“0xA 000 0xFFFF”
“10 000 0xFFFF”
模式匹配并使用IO编辑匹配流编辑T
在花括号中查找环境变量并将其替换为来自环境的价值。
导入系统。环境(getEnv)let bracevar=char'{'*>manyTill anySingle(char'}')::ParsecT无效字符串IO字符串streamEditT bracevar getEnv“-{HOME}-”
“-/home/jbrock-”
上下文相关模式匹配并使用编辑匹配流编辑T
将字符串中的第三个字母大写cap第三
分析器搜索单个字母,它需要记住运行了多少次只有在第三次找到字母时才能成功匹配。为了使解析器能够记住它运行了多少次,我们将使用州
单子这个mtl公司
包裹。(磨合全球温室气体排放指数
具有cabal v2-repl-b mtl
). 因为它已经有状态内存,这个解析器是“上下文敏感”语法的一个例子。
导入合格的控件。莫纳德。州。与MTL一样严格进口管制。莫纳德。州。严格(get、put、evalState)导入数据。字符(到上)let capThird::ParsecT无效字符串(MTL.State Int)字符串capThird=做x<-letterChar我<-得到设i'=i+1把我放进去如果i'==3,则纯[x]否则为空flip evalState 0$streamEditT capThird(pure.fmap to Upper)“a a a a”
“a a a a a”
模式匹配,编辑匹配,并使用计数编辑流编辑T
查找字符串中不超过三个字母并将其大写,然后返回编辑字符串以及大写字母的数量。要启用编辑器功能可以记住它大写了多少个字母,我们将运行流编辑T
在中州
来自的单子mtl公司
包裹。使用这个获得与Python相同功能的技术re.subn公司
.
导入合格的控件。莫纳德。州。与MTL一样严格进口管制。莫纳德。州。严格(get、put、runState)导入数据。字符(到上)让编辑三::字符->MTL。状态Int字符串editThree x=执行我<-得到如果i<3然后做放$i+1纯[toUpper x]else纯[x]flip runState 0$streamEditT letterChar editThree“a a a a”
(“A A A A A A”,3)
非自由模式重复
这不是此库的功能,但它是需要了解的有用技巧。
我们如何非贪婪地重复一个模式第页
就像我们在Regex一样通过写作p*?
?
通过使用直到_
组合器。重复图案第页
不贪婪地写直到_ p q
哪里q个
是解析器的整个其余部分。
例如,此解析失败的原因是许多的
重复图案letterChar(字母字符)
贪婪地。
翻转parse也许“aab”$doa<-多个字母Charb<-单个“b”纯(a,b)
没有什么
重复图案letterChar(字母字符)
不贪婪地使用多个井_
.
翻转parse也许“aab”$do(a,b)<-manyTill_ letterChar$do单个“b”纯(a,b)
Just(“aa”,“b”)
在壳牌公司
如果我们要有一个可行的塞德
更换,然后我们希望能够从命令行轻松使用它。这个堆栈脚本解释器该脚本将在流中查找十进制数,并将其替换为双精度数。
#!/usr/bin/env堆栈{-堆栈脚本--分解器lts-16--包装megaparsec--包替换-megaparsec-}--https://docs.haskellstack.org/en/stable/GUIDE/#script-口译员导入数据。无效导入文本。百万帕斯卡导入文本。百万秒差距。烧焦导入文本。Megaparsec公司。烧焦。莱克瑟导入替换。百万帕斯卡main=交互$streamEdit(decimal::Parsec Void String Int)(显示(*2))
如果你有Haskell工具组安装后,您可以将其复制到名为双重r.hs
和运行它。(第一次运行时,Stack可能需要下载依赖项。)
$chmod u+x倍r.hs$echo“1 6 21 107”|/双重r.hs2 12 42 214
选择
人们可能会考虑用一些库来代替这个库。
http://hackage.haskell.org/package/regex-applicative网站
http://hackage.haskell.org/package/pcre-heavy
http://hackage.haskell.org/package/lens-regex-pcre
http://hackage.haskell.org/package/regex
http://hackage.haskell.org/package/pipes-parse
http://hackage.haskell.org/package/stringsearch
http://hackage.haskell.org/package/substring解析器
http://hackage.haskell.org/package/pcre-utils
http://hackage.haskell.org/package/template
基准
这些基准旨在测量墙锁速度属于除了实际的图案匹配之外的一切。的速度图案匹配是百万帕斯卡和阿托帕塞克库。
基准任务是找到所有的单字符模式x个
在一个文本流并将其替换为返回常量的函数一串面向对象
。所以,就像正则表达式一样s/x/oo/g
.
我们有两个基准输入案例,我们称之为稠密的和稀疏的.
这个稠密的大小写是1兆字节的交替空格和x个
秒喜欢
x x x x x x x x xx x x×x x x
这个稀疏的大小写是一个兆字节的空格x个
在中间喜欢
x个
每个基准程序从标准输入
,替换x个
具有面向对象
,并将结果写入标准输出
。所用时间的测量方法为性能统计
,记录了最佳观测时间。
请参见更换基准点了解详细信息。
假设性问题
-
我们可以为编写这个库吗解析?
不,因为比赛
组合符不存在于解析(我哪儿也找不到。它能写吗?)
-
这是个好主意吗?
你可能有听说有人建议一元解析器更适合模式匹配输入流主要是信号流,正则表达式更好当输入流主要是噪声时。
这个库的前提是一元解析器非常适合查找杂乱文本流中的小信号模式。
我们不愿放弃通过限制提供的加速机会我们对常规语法的迷信由来已久机会,其中仍然大部分未开发.允许堆栈内存分配(也称为下推)的性能折衷自动机,也称为上下文无关语法)有争议的通用的程序设计语言.我想我们现在可以用与模式匹配语言相同的方式解决这个争议。