【问题标题】:Find and replace (part of) string in comment blocks with regex使用正则表达式在注释块中查找和替换(部分)字符串
【发布时间】:2013-08-06 15:39:43
【问题描述】:

我正在尝试查找可能出现在注释块中的某个字符串。该字符串可以是一个词,但它也可以是一个词的一部分。例如,假设我正在寻找“codex”这个词,那么这个词应该替换为“bindex”,但即使它是一个词的一部分,比如“codexing”。这应该改为“bindexing”。

诀窍是,只有当这个词在 comment 块内时才会发生这种情况。

/* Lorem ipsum dolor sit amet, codex consectetur adipiscing elit. */

This word --> codex should not be replaced

/* Lorem ipsum dolor sit 
 * amet, codex consectetur 
 * adipiscing elit. 
 */

/** Lorem ipsum dolor sit 
 * amet, codex consectetur 
 * adipiscing elit. 
 */

// Lorem ipsum dolor sit amet, codex consectetur adipiscing elit.

# Lorem ipsum dolor sit amet, codex consectetur adipiscing elit.

------------------- Below "codex" is part of a word -------------------

/* Lorem ipsum dolor sit amet, somecodex consectetur adipiscing elit. */

/* Lorem ipsum dolor sit 
 * amet, codexing consectetur 
 * adipiscing elit. 
 */

And here also, this word --> codex should not be replaced

/** Lorem ipsum dolor sit 
 * amet, testcodexing consectetur 
 * adipiscing elit. 
 */

// Lorem ipsum dolor sit amet, __codex consectetur adipiscing elit.

# Lorem ipsum dolor sit amet, codex__ consectetur adipiscing elit.

到目前为止,我所拥有的是这段代码:

$text = preg_replace ( '~(\/\/|#|\/\*).*?(codex).*?~', '$1 bindex', $text);

如您所见in this example,这并没有真正按照我想要的方式工作。当它位于多行 /* */ 注释块内时,它不会替换单词,有时它也会删除单词“codex”前面的所有文本。

如何改进我的正则表达式以使其符合我的要求?

【问题讨论】:

    标签: php regex preg-replace


    【解决方案1】:

    像这样使用子组应该可以工作;

    $str = preg_replace(
        '~(<!--[a-zA-Z0-9 \n]*)(MYWORD)([a-zA-Z0-9 \n]*-->)~s',
        '$1$3',
         $input
    );
    

    您只需为每种类型的评论创建一个单独的规则,并使用字符类限制评论中允许的可能字符(您可能更喜欢使用否定字符类)。

    【讨论】:

    • 这适用于 HTML cmets,每个评论块不会替换多个 codex。它也不包括换行符。
    • 再次调用它,直到它没有返回匹配项。
    • 如果你想在 cmets 中允许换行,你需要将它添加到字符类 '\n' 中,你真的应该用完整的代码来做这样的事情,而不是试图用正则表达式。通过使用.*,您将面临&lt;!-- block1 --&gt;MYWORD&lt;!--block2 --&gt; 被识别和替换的风险。
    【解决方案2】:

    正如之前在不同的 cmets 中编写的数百、数千甚至数百万次一样,正则表达式用于解析代码或在一个代码中搜索错误。

    考虑以下示例:

    // code to be replaced
    var a = "/*code to be replaced*/";
    
    /* code to be replaced
    var b = "*/code to be replaced"; */
    

    您无法使用 REGEX 解析代码(是的,找出字符串是否在注释块内称为解析)。

    找到一个解析器库,或创建一个您自己的精简库。如果您确实创建了一个,请记住脚本的所有不同用例,尤其是字符串将如何影响您的代码。

    【讨论】:

    • 我不是在解析代码,而是在搜索一个以(/*|//|#) 开头的字符串。 现代正则表达式语言无所不能。正如给定答案所证明的那样。这不是我要解析的 HTML 或 XML,也不是那些行中的任何内容。
    【解决方案3】:

    由于您在此处处理多行文本,您应该使用s 修饰符 (DOTALL) 来匹配多行文本。也不需要转义正斜杠。

    试试这个代码:

    $text = preg_replace ( '~(//|#|/\*).*?(codex).*?~s', '$1 bindex', $text );
    

    【讨论】:

    • 非常感谢,这似乎正是我想要的! :)
    【解决方案4】:
    $text = preg_replace ( '~(//|#|/\*)(.*?)(codex).*?~s', '$1$2bindex', $text );
    

    这不会像 anubhava 的回答那样删除“codex”之前的 cmets

    【讨论】:

      【解决方案5】:

      [编辑] 我编辑了这个答案,因为尽管我当时天真无情,但我决定承认用简单或复杂的 preg_replace 解决这个问题是不可能的!对支持我的回答的好人深表歉意。[/EDIT]

      回答这个问题:改进你的模式是不可能的,用preg_replace 根本不可能做到这一点!您必须为preg_replace_callback 构建一个匹配整个评论的模式,然后继续替换回调函数中出现的codex

      此版本可以处理任何类型的 cmets,并且不会因此类字符串 /**/ codex /**//*xxxx codex codex xxxx*/ 或任何其他陷阱而失败。

      $result = preg_replace_callback('~/\*.*?\*/|#\N+|//\N+~s', function($m) {
          return stri_replace('codex', 'bindex', $m[0]);
      }, $subject);
      

      请注意,除了这种模式更简单之外,它也很有效,因为交替的每个分支都是“锚定的”,因为它们以文字字符开头。因此,该模式受益于自动优化。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-07
        • 2021-05-18
        • 2019-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-27
        • 2016-08-16
        相关资源
        最近更新 更多