【问题标题】:Regex to match keyword if not enclosed by curly braces如果没有用大括号括起来,则正则表达式匹配关键字
【发布时间】:2011-05-19 09:23:18
【问题描述】:

在 PHP 变量中,我有一些包含一些关键字的文本。这些关键字目前大写。我希望它们保持大写并用大括号括起来,但只有一次。我正在尝试编写升级代码,但每次运行它都会将关键字包装在另一组大括号中。

如果它是{KEYWORD},我需要使用什么正则表达式来单独匹配关键字而不匹配它。

例如,文本变量是:

$string = "BLOGNAME has posted COUNT new item(s),

TABLE

POSTTIME AUTHORNAME

You received this e-mail because you asked to be notified when new updates are posted.
Best regards,
MYNAME
EMAIL";

而我的升级代码是:

$keywords = array('BLOGNAME', 'BLOGLINK', 'TITLE', 'POST', 'POSTTIME', 'TABLE', 'TABLELINKS', 'PERMALINK', 'TINYLINK', 'DATE', 'TIME', 'MYNAME', 'EMAIL', 'AUTHORNAME', 'LINK', 'CATS', 'TAGS', 'COUNT', 'ACTION');
foreach ($keywords as $keyword) {
    $regex = '|(^\{){0,1}(\b' . $keyword . '\b)(^\}){0,1}|';
    $replace = '{' . $keyword . '}';
    $string = preg_replace($regex, $replace, $string);
}

我的 REGEX 目前根本无法正常工作,它正在删除一些空格,并且在每次运行时都会在大多数(但不是全部)关键字周围放置更多的花括号。我究竟做错了什么?有人可以纠正我的正则表达式吗?

【问题讨论】:

  • 只是一个建议。您可以通过将其放入一个正则表达式并说 ... (BLOGNAME|BLOGLINK|TITLE|POST|etc) 而不是单独检查每个表达式来稍微提高效率。
  • PHP 代码如何知道它正在替换哪个单词?
  • 在正则表达式替换的上下文中,当您将表达式放在括号中时,您“捕获”了该表达式所引用的值。然后,您可以使用$x 在替换字符串中引用捕获的值,其中“x”是捕获的表达式的索引,$1 表示第一次捕获,$2 表示第二次,依此类推。示例:preg_replace("/.* Customer#([0-9]+)/", "I captured the number $1", "This is for Customer#1234"); 将返回“我捕获了数字 1234”。
  • 如果您对上面给出的表达式 (BLOGNAME|BLOGLINK|etc) 执行相同的操作,那么您可以将捕获的值(您的关键字)引用为替换字符串中的 $1。类似:preg_replace($expression, "{$1}", $string);。您可能需要使用大于 1 的值,具体取决于您选择的表达式正在执行多少次捕获。
  • 最新答案显示了如何做到这一点。

标签: php regex regex-negation


【解决方案1】:

您正在寻找negative assertions。它们不是像在字符类中那样使用^ 语法编写的,而是使用(?<!...)(?!...) 编写的。在你的情况下:

'|(?<!\{)(\b' . $keyword . '\b)(?!\})|';

【讨论】:

    【解决方案2】:
    • 如果关键字不包含特殊字符,它将起作用。
    • (A1) 行可以从正则表达式中删除,如果源文本不能包含 {keyword} 或需要在结果文本中的关键字周围留下“{}”符号({keyword} 需要 {{keyword}} 格式化为示例)

    $text = <<<EOF
    BLOGNAME has posted COUNT new item(s),
    
    TABLE
    
    POSTTIME AUTHORNAME
    
    You received this e-mail because you asked to be notified when new updates are posted.
    Best regards,
    MYNAME
    EMAIL
    EOF;
    
    $aKeywords = array('BLOGNAME', 'BLOGLINK', 'TITLE', 'POST', 'POSTTIME', 'TABLE', 'TABLELINKS', 'PERMALINK', 'TINYLINK', 'DATE', 'TIME', 'MYNAME', 'EMAIL', 'AUTHORNAME', 'LINK', 'CATS', 'TAGS', 'COUNT', 'ACTION');
    $keywords = implode('|', $aKeywords);
    
    $reSrch = '/
                (?<!\{)             # (A1) prev symbol is not {
                \b                  # begin of word
                ('.$keywords.') # list of keywords
                \b                  # end of word
                (?!\{)              # (A1) next symbol is not {
                /xm';               //  m - multiline search & x - ignore spaces in regex
    
    $reRepl = '{\1}';
    
    $result = preg_replace($reSrch, $reRepl, $text);
    
    echo '<pre>';
    // echo '$reSrch:'.$reSrch.'<hr>';
    echo $result.'<br>';
    

    【讨论】:

    • 最初无法让它工作,但这一定是我的问题,因为我现在已经让它工作了。由于我的原始代码将循环使用 18 个关键字并每次执行 6 个 preg_replace 调用,因此我怀疑您的方法会更有效率,所以我感谢您。
    • @Matt Robinson:欢迎您。询问,如果您需要解释。
    【解决方案3】:

    为什么是正则表达式?只需使用str_replace

    foreach ($keywords as $k) {
      $string = str_replace($k, '{'.$k.'}', $string);
    }
    

    【讨论】:

    • 因为如果您有重叠的键,它将无法正常工作。 str_replace("POST", "{POST}", $string); 会将{POSTTIME} 变成{{POST}TIME},这很糟糕。
    • 啊,对。如果您向$k 添加空格,例如" $k "?嗯,当关键字在字符串的开头或结尾时,它不会匹配。呸。
    • 你明白了。正则表达式经常被滥用和邪恶,但在这里它们是有道理的(即使预期的用途有点奇怪):)
    • @Jeff,当您说用法有点奇怪时,您是否认为有更好的方法?我全神贯注!
    • 不,只是给已经定义的关键字添加大括号似乎有点没有意义。显然,您将用实际值替换它们,但在这种情况下,为什么还要费心戴上大括号呢?
    猜你喜欢
    • 2010-09-22
    • 2015-10-28
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多