V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
honkew
V2EX  ›  PHP

小白问一个正则匹配的问题

  •  1
     
  •   honkew · 2022-03-18 16:20:19 +08:00 · 2751 次点击
    这是一个创建于 984 天前的主题,其中的信息可能已经有所发展或是发生改变。

    小白问一个正则匹配的问题

    print(print(print().print()));

    需要匹配 print 中间的内容 print(print().print())

    需要保持括号成对的 小括号的数量未知!

    是不是用分组能解决,但我不知道该怎么做

    第 1 条附言  ·  2022-03-18 18:11:56 +08:00
    追加一下

    part("asdf",print("asdf",(2048+1024)/2))
    提取 print("asdf",(2048+1024)/2)
    print_r(print($a[(128 + 256) / 2], $a[(2048 + 256) / 2]))
    提取 print($a[(128 + 256) / 2], $a[(2048 + 256) / 2])
    第 2 条附言  ·  2022-03-18 19:02:11 +08:00
    看到一篇文章 https://my.oschina.net/zhubaoxin/blog/1590198
    用(?<-Nested>)能实现吗,有点理解不了

    A. 匹配到嵌套 div 起始标签<div ,这个时候,需要将其捕获到 Nested 分组。
    B. 匹配到嵌套 div 起始标签的闭合标签,这个时候,需要将之前的 Nested 分组释放
    C. 其他任意文本。注意,需要使用.*?方式关闭贪婪匹配,否则最后的闭合标签可能会过度匹配

    使用(RegEx1|RegEx2|RegEx3)*这种方式,可以将几个条件以或的形式组合起来,然后再取若干次匹配结果,最终再匹配闭合标签。其中(?<-Nested>)是表示释放之前捕获的 Nested 分组。确切的语法是(?<N-M>)即使用 N 分组替换掉 M 分组,如果 N 分组没有指定或不存在,则释放 M 分组。
    30 条回复    2022-03-19 14:53:43 +08:00
    Kasumi20
        1
    Kasumi20  
       2022-03-18 16:30:52 +08:00
    /print\((.*)\);/
    honkew
        2
    honkew  
    OP
       2022-03-18 16:31:19 +08:00
    来个大神看看, 别沉了啊
    honkew
        3
    honkew  
    OP
       2022-03-18 16:31:59 +08:00
    @Kasumi20 结尾不一定是); 可能是)
    MooRider
        4
    MooRider  
       2022-03-18 16:32:32 +08:00
    那就加个?呗, 0 个或 1 个
    honkew
        5
    honkew  
    OP
       2022-03-18 16:34:05 +08:00
    @MooRider 呃,重点要保证括号是成对的,不能确定有多少个 )
    liuhan907
        6
    liuhan907  
       2022-03-18 16:38:32 +08:00
    @honkew
    括号不是可以正则匹配的。
    theoda
        7
    theoda  
       2022-03-18 16:38:39 +08:00
    @honkew 举个不成对的例子呢
    cpstar
        8
    cpstar  
       2022-03-18 16:45:33 +08:00
    OP 得多提供几种用于匹配的字符串,单独这一个,很多情况无法覆盖
    constexpr
        9
    constexpr  
       2022-03-18 16:47:49 +08:00
    这个需要支持递归的正则了, 不建议用正则
    samv2
        10
    samv2  
       2022-03-18 17:17:45 +08:00
    print\((.+)\)[^)]?

    分组取$1
    imdong
        11
    imdong  
       2022-03-18 17:23:20 +08:00 via iPhone
    \)$ 呢?
    darklights
        12
    darklights  
       2022-03-18 18:17:11 +08:00
    9 楼正解,要用递归模式,然而我不会。
    PHP 也支持,文档:www.php.net/manual/en/regexp.reference.recursive.php 。只能帮到这了。
    说实话,用正则解决这类问题不如 PEG 直观。
    GeruzoniAnsasu
        13
    GeruzoniAnsasu  
       2022-03-18 18:42:49 +08:00
    经典正则 vs 括号配对


    正则表达式无法匹配成对的括号。 搜索关键词: 泵引理 ( Pumping lemma )
    jfcherng
        14
    jfcherng  
       2022-03-18 18:51:21 +08:00
    總覺得追加的測試用例和原文給的測試用例並不存在相同規則。
    樓主追加的測試用例並不符合最一開始說的「需要匹配 print 中间的内容」
    jfcherng
        15
    jfcherng  
       2022-03-18 18:52:44 +08:00
    print(\(((?>[^()]+)|(?-2))*\)) 符合追加內容,但不符合最一開始給的例子
    honkew
        16
    honkew  
    OP
       2022-03-18 19:06:33 +08:00
    @jfcherng 是我没有表达清楚 大概意思就是匹配 print() 中的内容但是里面的括号要成对出现直到结束,里面的括号数量未知

    print(()) 对的
    print(print()) 对的
    print(print(),()) 对的
    print(print(),()()) 对的
    GuuJiang
        17
    GuuJiang  
       2022-03-18 19:18:35 +08:00
    参见我在 https://v2ex.com/t/820095#reply6 里的回答
    正则表达式不是万能的,只能匹配正则语言,而非正则语言中最经典的一个例子就是成对的括号
    自己老老实实用个栈来做吧,比正则表达式简单多了
    jfcherng
        18
    jfcherng  
       2022-03-18 19:19:15 +08:00
    @honkew 簡單來說

    為什麼是返回 print(print().print())
    而不是返回 print(print(print().print()))
    jfcherng
        19
    jfcherng  
       2022-03-18 19:21:02 +08:00
    如 #12 所說,PHP 用的正則是可以遞歸的,所以可能有解,例如我給出的 #15 。但我沒看出 LZ 結果的規則。
    honkew
        20
    honkew  
    OP
       2022-03-18 19:22:15 +08:00
    @jfcherng 对,应该是 print(print(print().print()))
    jfcherng
        21
    jfcherng  
       2022-03-18 19:22:26 +08:00
    當然以後你可能也不知道當初自己的正則到底在寫什麼 (狗頭
    jfcherng
        22
    jfcherng  
       2022-03-18 19:24:24 +08:00
    @honkew #20 那你用 $15 那個就行了。不過字串裡有不成對的括號就炸了
    honkew
        23
    honkew  
    OP
       2022-03-18 19:28:37 +08:00
    @jfcherng 貌似可以耶,我学习下这个
    lujjjh
        24
    lujjjh  
       2022-03-18 19:38:57 +08:00
    正确的回答是,这个问题不适合用正则表达式解决。

    > Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems. - Jamie Zawinski
    iqfEmhuNidBhDfWo
        25
    iqfEmhuNidBhDfWo  
       2022-03-18 20:25:24 +08:00
    看起来骏马金龙博客的“分组命名捕获”可以满足你的需求,这博主我是真佩服
    shyrock
        26
    shyrock  
       2022-03-18 22:16:43 +08:00
    @darklights #12 PEG 是啥?
    darklights
        27
    darklights  
       2022-03-18 22:26:42 +08:00
    @shyrock Parsing Expression Grammar 解析表达文法
    xiangyuecn
        28
    xiangyuecn  
       2022-03-19 00:14:31 +08:00
    print(")text( ((( )))))))(((((())))", (1+1+(1+1))) 神仙难救
    LeeReamond
        29
    LeeReamond  
       2022-03-19 11:42:34 +08:00
    @lujjjh 粗看下题设未脱离状态机可解决的范畴
    lujjjh
        30
    lujjjh  
       2022-03-19 14:53:43 +08:00   ❤️ 1
    @LeeReamond 有限状态机无法解决括号匹配问题,需要有无限个状态(不在括号里、在一对括号里、在两对括号里……)。某些语言里的正则可能有一些特有特性能解决这种递归 /平衡的问题,但括号匹配仍不属于常规意义里的正则语言。

    OP 实际上提出了一个 XY problem ,可以预见的是,即便是顺着思路强行用正则实现,仍然会出现 BUG 。因为这里的状态不只是括号,还有是否在字符串里、是否在注释里等等。我猜测 OP 真正需要的是一个完备的 PHP parser ,但最终想实现什么不得而知。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5719 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:34 · PVG 09:34 · LAX 17:34 · JFK 20:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.