Haskell 用于子正则表达式匹配的TDFA(标记DFA)中标记转换的标记操作

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

我是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.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概念,如果我重写regex
R=(tag1b | tag2bb | tag3bbb | tag4bbbbb)*
然后尝试将其与输入字符串匹配=
“bbbbbb”
,那么我的兴趣是看看这些标记{1,2,3,4}执行了多少次
来匹配regex
R
。同样,在给定的输入字符串上,“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
    非常感谢您的反馈。然而,与此同时,我发现了一些更有趣的事情。不管怎样,你的回答对我来说很重要,好吗。再次感谢您……)