Haskell 用于子正则表达式匹配的TDFA(标记DFA)中标记转换的标记操作
我是Haskell编程的初学者。我试图使用Haskell programming+TDFA为正则表达式后端匹配正则表达式的字符串。而且,我成功地完成了子正则表达式匹配操作,但没有使用TDFA中提出的标记概念。例如,请参阅以下代码Haskell 用于子正则表达式匹配的TDFA(标记DFA)中标记转换的标记操作,haskell,Haskell,我是Haskell编程的初学者。我试图使用Haskell programming+TDFA为正则表达式后端匹配正则表达式的字符串。而且,我成功地完成了子正则表达式匹配操作,但没有使用TDFA中提出的标记概念。例如,请参阅以下代码 {-# LANGUAGE MagicHash #-} import Control.Monad import Data.Array import qualified Data.Text as T import Text.Regex.TDFA import Text.R
{-# LANGUAGE MagicHash #-}
import Control.Monad
import Data.Array
import qualified Data.Text as T
import Text.Regex.TDFA
import Text.Regex.TDFA.Common
str = "bbbb" :: String
regex = "(b|bb|bbb|bbbb)*" :: String
/*regex=“(tag1b | tag2bb | tag3bbb | tag4bbbb)*”::String-->*/
main = do
if str =~ regex then putStrLn "matched" else putStrLn "no matches"
let matches = getAllTextMatches (str =~ regex) :: Array Int (Array Int String)
print matches
-- Output: array (0,1) [(0,array (0,1) [(0,"bbbb"),(1,"bbbb")]),(1,array (0,1) [(0,""),(1,"")])]
let matches = getAllTextMatches $ str =~ regex :: [Array Int String]
print matches
-- Output: [array (0,1) [(0,"bbbb"),(1,"bbbb")],array (0,1) [(0,""),(1,"")]]
let matches = getAllTextMatches $ str =~ regex :: Array Int [String]
print matches
-- Output: array (0,1) [(0,["bbbb","bbbb"]),(1,["",""])]
let matches = getAllTextMatches $ str =~ regex :: Array Int String
print matches
-- Output: array (0,1) [(0,"bbbb"),(1,"")]
let matches = getAllTextMatches $ str =~ regex :: [String]
print matches
-- Output: ["bbbb",""]
let matches = str =~ regex :: [[String]]
print matches
-- Output: [["bbbb","bbbb"],["",""]]
let matches = getAllTextMatches $ str =~ regex :: Array Int (MatchText String)
print matches
-- Output: array (0,1) [(0,array (0,1) [(0,("bbbb",(0,4))),(1,("bbbb",(0,4)))]),(1,array (0,1) [(0,("",(4,0))),(1,("",(-1,0)))])]
-- Using getAllMatches
let matches = getAllMatches $ str =~ regex :: Array Int MatchArray
print matches
-- Output: array (0,1) [(0,array (0,1) [(0,(0,4)),(1,(0,4))]),(1,array (0,1) [(0,(4,0)),(1,(-1,0))])]
let matches = getAllMatches $ str =~ regex :: Array Int (MatchOffset,MatchLength)
print matches
-- Output: array (0,1) [(0,(0,4)),(1,(4,0))]
let matches = getAllMatches $ str =~ regex :: [(MatchOffset,MatchLength)]
print matches
-- Output: [(0,4),(4,0)]
无论如何,现在,我实际上非常感兴趣地看到TDFA上的标记操作在为接受的输入字符串匹配子表达式时是如何执行的。比如说,
我们有一个正则表达式,R=(b | bb | bbb | bbbbb)*
和输入字符串=“bbbbbb”
。因此,使用TDFA概念,如果我重写regexR=(tag1b | tag2bb | tag3bbb | tag4bbbbb)*
然后尝试将其与输入字符串匹配=“bbbbbb”
,那么我的兴趣是看看这些标记{1,2,3,4}执行了多少次来匹配regexR
。同样,在给定的输入字符串上,“bbbb”
,第一个b
将是匹配的tag1
的范围,与输入子字符串“bbbb”
相同,“bbbbbb”将是tag2
的范围,依此类推。这就是如何,如果我们现在考虑完整的给定输入字符串<代码>“BBBB”,那么<代码> TAG4将给出它的结果,同时给出<<代码> BBB <代码>“BBBB”< /> >匹配<代码> TAG3的范围,与<代码>“BB”<代码> > BBBB”相同。匹配了tag2
的范围,最后“bbbb”的“b”
匹配了tag1
的范围。因此,我希望使用TDFA模块查看这些操作。就这样。我的意思是,为了将子正则表达式与给定接受输入字符串的正则表达式匹配,这些标记必须更新多少次。就这样
因此,任何形式的帮助对我都是很大的……:)
附言:这对Haskell初学者来说是一个挑战,因此需要寻找Haskell黑客。我的意思是明智的…:)无论如何,希望最好…:)不可能将显式标记写入传递给Regex-TDFA的regexp。正则表达式TDFA支持,在POSIX中,子匹配提取涉及捕获组(即括号中的子表达式)。您可以将捕获组与Regex TDFA一起使用,如下所示:
Prelude Text.Regex.TDFA> "bbbb" =~ "((b)|(bb)|(bbb)|(bbbb))*" :: MatchArray
array (0,5) [(0,(0,4)),(1,(0,4)),(2,(-1,0)),(3,(-1,0)),(4,(-1,0)),(5,(0,4))]
这里您可以看到表达式有6个捕获组:(b)
、(bb)
、(bbb)
、(bbbbbb)
、((b)|(bbb)|(bbbbbbbb))
以及整个regexp,它们在POSIX中始终是隐式的第一组
整个regexp在偏移量0
和跨度4
符号处匹配
((b)|(bb)|(bbb)|(bbbb))
匹配偏移量0
和跨距4
符号
(b)
不匹配——因此起始偏移量-1
和匹配长度0
同样地,(bb)
也不匹配
同样地,(bbb)
也不匹配
最后,(bbbb)
在偏移量0
处匹配,并跨越4
符号
您也可以将子匹配提取用于其他接口:
Prelude Text.Regex.TDFA> "bbbb" =~ "((b)|(bb)|(bbb)|(bbbb))*" :: [[String]]
[["bbbb","bbbb","","","","bbbb"],["","","","","",""]]
这些标记是由Regex-TDFA内部算法隐式添加的——它们是对用户隐藏的实现细节。如果您想要的是使用Haskell regexp提取子匹配,那么此时应该停止阅读。然而,如果您对Regex TDFA的操作理论感兴趣,那么您的问题的答案就要复杂得多
2000年,Regex TDFA基于标记DFA的概念
《正则表达式TDFA》的作者Chris Kuklewicz扩展了Ville算法以支持POSIX消歧语义。他在2007年非正式地描述了他的消歧算法,并对其进行了形式化或开发
Kuklewicz消歧算法是在中采用的,并在中进行了形式化(我恰好是该算法的作者)。RE2C还支持最左端的贪婪消歧语义,并允许您执行以下操作。另请参阅的简单示例或更复杂的示例,以了解该想法
回到你的问题:
为了使子正则表达式与给定接受输入字符串的正则表达式匹配,这些标记必须更新多少次
答案是,它取决于给定正则表达式的非确定性程度(有关解释,请参见第16页)。对于简单的标记确定性regexp,这是一个微不足道的常量时间开销。对于有界重复的病理病例,参见论文中的示例5(第21页)。另请参见基准测试(第27-29页),它们表明,在实际测试中,子匹配提取的开销相当小
还要注意的是,Regex-TDFA使用了延迟的去模糊化,也就是说,确定和POSIX消歧的所有开销都在运行时,因此子匹配提取的总体开销大于RE2C情况
最后,您可以使用/Text/Regex/TDFA/TDFA.hs
中定义的testedfa
调试函数来探索Regex-TDFA内部,并进一步调整它以打印您需要的信息。@skvadrik
非常感谢您的反馈。然而,与此同时,我发现了一些更有趣的事情。不管怎样,你的回答对我来说很重要,好吗。再次感谢您……)