代码之家  ›  专栏  ›  技术社区  ›  Andrew

用pcre regex提取代码段

  •  0
  • Andrew  · 技术社区  · 16 年前

    我正在处理可使用MySQL和PHP搜索的长段文本。我希望能够找到并只突出显示相关的搜索词,并使用regex来隔离它们。

    例如,我想转换一个lorem ipsum段落,

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
    incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud 
    exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor 
    in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur 
    sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est 
    laborum.
    

    在搜索“dolor”时会变成这样,

    Lorem ipsum *dolor* sit amet ... labore et *dolor*e magna aliqua ... aute irure *dolor* in reprehenderit ... esse cillum *dolor*e eu fugiat ...
    

    在学期前后有两个(或多个)单词。

    到目前为止我有这个

    search  - .*?(\w+?\b\s){2}(dolor)(\w+?\b\s){2}.*?
    replace - ... $1*$2*$3... 
    

    但它并不完全有效;它只在前后找到一个单词(尽管有2),当搜索字符串位于字符串(或句子)的开头或结尾时失败,并且不会在最后找到的搜索字符串实例后删除段落的其余部分。

    最好的方法是什么?

    谢谢!

    3 回复  |  直到 16 年前
        1
  •  1
  •   Jeremy Smyth    16 年前

    一些变化:

    ((\w+\b\s*){2})(dolor)(\w*\s*(\w+\b\s*){2})
    
    ...$1*$3*$4...
    

    首先, {2} 在这两种情况下,乘数都需要包含在内存中,以确保记住这两个单词。这意味着我们可以忽略 $2 当读回它时( $5 现在包含最后匹配的单词)。

    其次,在“dolor e”和其他任何与dolor\w+有关的情况下,终端“e”本身就变成了一个单词;为了与上面的规范相匹配,我添加了\w*\s*,以便在剩余的单词中捕获任何单词结尾字符和终端空间。

    否则,非贪心的“?”这里不需要char,因为您已经在\w+的末尾指定了\b,所以我也清除了它们。

        2
  •  0
  •   Dave Sherohman    16 年前

    它在开始/结束时失败,因为您指定(或至少尝试指定…)匹配必须正好包含两个前导和尾随上下文的单词。如果你的“多尔”是第一个词,那么前面就没有了,所以比赛失败了。改变 {2} {0,2} 应该修复那个部分。

    另外一件事很快就显得与众不同,那就是你使用 \w+?\b\s . 你可能是说 \w*\b\s . * 表示“匹配零或多个”,相当于您试图指定的“可选匹配一个或多个” +? . 还要注意,除非您更改 \s \s+ ,它将在由多个空格分隔的单词上失败。标点符号或其他既不是单词也不是空白字符的字符也存在潜在问题。

    不过,归根结底,我认为正则表达式可能不是实现所要实现的目标的最佳方法,或者至少不是靠它们自己。最有效的方法可能是建立一个自定义的全文搜索,使用包含单词文本的反向索引、它的位置(这样您就可以按正确的顺序获取它们)和上下文中突出显示的单词(这样您就可以将它们连接在一起以获得最终的结果)。

    如果这不是一个选项,我将把文本拆分成一组单词,然后在其中扫描目标单词。这不仅使处理上下文需求变得更容易,我还希望它比纯regex解决方案运行得更快,因为它将严重减少对回溯的潜在需求。(不过,在文本上运行两次传递(第一次传递将文本拆分为一组单词,第二次传递将每个单词与搜索词进行比较)可能会使事情发生相反的变化。)

        3
  •  0
  •   jitter    16 年前

    关于只有一个词匹配的问题:

    PHP PCRE 文档

    当捕获子模式为 重复,捕获的值是 匹配最终结果的子字符串 迭代。

    例如

    String
    "tweedledum tweedledee"
    
    Regex
    (tweedle[dume]{3}\s*)+
    
    Captured value
    tweedledee
    

    这个regex应该能让你更亲近一点。

    .*?(\w+\b\s*\w+\b\s*)?(dolor)(\w*\s*\w+\b\s*\w+\b)?.*?
    

    在字符串末尾或开头不适用于Dolor。不处理非空格或非单词字符。不能处理多个Dolor实例相互跟随的问题(例如Dolor Dolor Dolor)。当Dolor处于“2字范围”时无法处理(例如Lorem Ipsum Dolor Amet Dolor)。我现在想不出的其他特殊情况也会被解开。