【问题标题】:Lowercase everything except when between brackets小写除括号之间的所有内容
【发布时间】:2012-02-10 14:08:18
【问题描述】:

考虑以下字符串:

LoReM {FOO} IPSUM dolor {BAR} Samet {fooBar}

我正在寻找一种将所有内容小写的方法 - 除了 {括号} 之间的内容应该被忽略。所以想要的输出是:

lorem {FOO} ipsum dolor {BAR} samet {fooBar}

在另一个主题@stema 指向http://de2.php.net/manual/en/functions.anonymous.php 来实现这样的事情,但我不明白如何:

echo preg_replace_callback('~\{.*?\}~', function ($match) {
  return strtolower($match[1]);
}, 'LoReM {FOO} IPSUM dolor {BAR} Samet {fooBar}');

这只会返回没有括号 {tags} 的字符串,甚至不会小写。谁能帮我解决这个问题?非常感谢任何帮助:)

【问题讨论】:

标签: php regex


【解决方案1】:

你的表达必须抓住其他部分:

echo preg_replace_callback('~^.*?{|}.*?{|}.*?$}~', function ($match) {
  return strtolower($match[0]);
}, 'LoReM {FOO} IPSUM dolor {BAR} Samet {fooBar}');

【讨论】:

    【解决方案2】:

    将您的正则表达式更改为:

    ~(?:^|})(.*?)(?:\{|$)~
    

    解释:

    ~           : delimiter
      (?:       : start non capture group
        ^|}     : begin of string or }
      )         : end of group
      (         : start capture group #1
        .*?     : any number of any char. non greedy
                  (ie: all char outside of {})
      )         : end of group
      (?:       : start non capture group
        \{|$    : { or end of string
      )         : end of group
    ~           : delimiter
    

    【讨论】:

      【解决方案3】:

      使用preg_replace_callback() 可能是最好的方法。您只需要将正则表达式改成这样:

      ~(^|\})(.*?)(\{|$)~
      

      然后返回这个:

      return $match[1] . strtolower($match[2]) . $match[3];
      

      【讨论】:

      • @hakre:它可以很好地处理这种情况吗?
      • @drrcknsln:如果您在原始字符串中实际使用大写字母,则不会:Tree } Makes Me Wonder {FOO} { Sick String - codepad.viper-7.com/x1Kihk
      • @hakre:啊,我想我现在明白你的意思了。它不能正确处理 ^([^{]*)\}\{([^}]*)$ 情况。
      • drrcknlsn 这是什么黑魔法!你能向我解释一下它是如何工作的吗?我不明白只有 $match[2] 是如何小写的,但是这些单词被放在正确的位置放回字符串中? @hakre - 这种情况永远不会发生。我可以肯定地说所有 {tags} 都有一个开始和结束括号(其中没有括号)。
      • @Reveller:基本上,这个正则表达式忽略了{} 之间的内容。我们不关心替换它,因为我们想保持原样。相反,我们查找/替换位于}{ 之间的文本,或行首和{,或} 和行尾。换句话说,我们不理会{tags},并匹配它们周围的所有内容。
      【解决方案4】:

      您想要匹配除{} 之外的所有字符。然后将匹配替换为strtolower

      为此,您需要创建一个匹配除括号对之外的所有内容的模式:

      ~(?:{\w+}(*SKIP)(*FAIL))|[^{}]+~
      

      这将跳过(并删除)所有括号对,但匹配所有非括号字符({}。然后您可以使用回调函数将匹配项小写:

      $str = '{LoReM {FOO} IPSUM { dolor {BAR} Samet {fooBar} Tou}Louse';
      
      $out = preg_replace_callback('~(?:{\w+}(*SKIP)(*FAIL))|[^{}]+~', function($m)
          {return strtolower($m[0]);}, $str)
          ;
      
      echo $out;
      

      Demo,输出:

      {lorem {FOO} ipsum { dolor {BAR} samet {fooBar} tou}louse
      

      如示例所示,非关联括号不是负担。此模式还指定了括号对应如何编写,\w 代表任何单词字符,如果它不合适(例如在您的 duplicate question 中),您可以将其替换为完全满足您需求的任何字符类。

      这实际上与已回答的问题非常相似:How to let regex ignore everything between brackets? - 它实际上是我在回答更详细后看到的完全相同的副本。

      【讨论】:

        【解决方案5】:

        这个怎么样。

        $input = 'LoReM {FOO} IPSUM dolor {BAR} Samet {fooBar}';
        preg_match_all('~\{.*?\}~', $input, $matches);
        $output = strtolower($input);
        foreach ($matches[0] as $match) {
          $output = str_replace(strtolower($match), $match, $output);
        }
        

        【讨论】:

        • 这有很多副作用。它只会偶然起作用,而不是设计。
        【解决方案6】:

        您可以将preg_replace() 与 PREG_REPLACE_EVAL 修饰符一起使用,如下所示:

        $string  = 'LoReM {FOO} IPSUM dolor {BAR} Samet {fooBar}';
        $pattern = '/(?<![[:word:]{])[[:word:]]*?(?![[:word:]}])/e';
        echo preg_replace($pattern, 'strtolower($0)', $string);
        

        然后,模式匹配的所有内容都将通过在匹配项上评估 strtolower() 来替换。如果您想了解正则表达式,最容易从中间开始,(为了便于阅读,我用空格分隔了块)

        (?<![[:word:]{]) [[:word:]]*? (?![[:word:]}])
        ^                ^            ^
        |                |            |
        |                +-- match any amount of word characters (alphanums)
        |                             |
        +-- that are not preceded by a word character or {
                                      |
                                      +-- and are not followed by a word character or }
        
        Where word characters are alphanumeric characters and underscores.
        

        【讨论】:

          【解决方案7】:

          这是 REGEX 遇到很多麻烦的问题类型。更好的解决方案是编写一个按字符读取字符并可以切换状态的解析器。

          • 以小写模式启动。以小写形式输出每个读取的字符。
          • 如果在小写模式下读取{ 字符,请切换到大写模式。
          • 如果在大写模式下读取} 字符,则切换到小写模式。

          请记住,如果要处理嵌套大括号,它会更加复杂。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-10-24
            • 1970-01-01
            • 1970-01-01
            • 2011-11-30
            • 2020-02-28
            • 2022-11-03
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多