【问题标题】:preg_replace to capitalize a letter after a quotepreg_replace 在引号后大写字母
【发布时间】:2010-04-14 14:42:28
【问题描述】:

我有这样的名字:

$str = 'JAMES "JIMMY" SMITH'

我运行strtolower,然后运行ucwords,它返回:

$proper_str = 'James "jimmy" Smith'

我想将第一个字母是双引号的单词的第二个字母大写。这是正则表达式。看来 strtoupper 不起作用 - 正则表达式只是返回未更改的原始表达式。

$proper_str = preg_replace('/"([a-z])/',strtoupper('$1'),$proper_str);

有什么线索吗?谢谢!!

【问题讨论】:

  • 你期待什么输出?
  • 我认为:詹姆斯“吉米”史密斯。目前 ucwords() 没有将 Jimmy 的第一个字母大写,因为它不能将双引号识别为单词边界字符。

标签: php regex


【解决方案1】:

可能最好的方法是使用preg_replace_callback()

$str = 'JAMES "JIMMY" SMITH';
echo preg_replace_callback('!\b[a-z]!', 'upper', strtolower($str));

function upper($matches) {
  return strtoupper($matches[0]);
}

您可以在preg_replace() 上使用e (eval) 标志,但我通常建议不要这样做。尤其是在处理外部输入时,它可能非常危险。

【讨论】:

  • 我得到一个错误,'upper' 不是一个有效的回调。当我用'strtoupper'替换'upper'时,我得到'ARRAY'而不是大写字母'J'
  • @Summer 那么你没有按照我的代码 sn-p 定义 upper() 函数。
  • 正如@mcfedr 所说,从PHP 5.3 开始,您可以使用anonymous functionpreg_replace_callback(..., function($matches) { ...
  • 绝对是现在最好的办法,/e已经不再支持了。
【解决方案2】:

使用preg_replace_callback - 但是您不需要添加额外的命名函数,而是使用匿名函数。

$str = 'JAMES "JIMMY" SMITH';
echo preg_replace_callback('/\b[a-z]/', function ($matches) {
     return strtoupper($matches[0]);
}, strtolower($str));

/e 的使用自 PHP 5.5 起已被弃用,并且在 PHP 7 中不起作用

【讨论】:

    【解决方案3】:

    使用e modifier 来评估替换:

    preg_replace('/"[a-z]/e', 'strtoupper("$0")', $proper_str)
    

    其中$0 包含整个模式的匹配,所以" 和小写字母。但这并不重要,因为" 在通过strtoupper 发送时不会改变。

    【讨论】:

    • 我认为我让它变得比strtoupper('"')==='"' 需要的更难。 ;-)
    • 显然e 选项是一个严重的安全漏洞,他们建议改用preg_replace_callback()。仅供参考。
    • +1 Buttle 评论,+1 cletus 和 mcfedr 的回答,因为它不会造成安全漏洞
    • 此功能自 PHP 5.5.0 起已弃用。强烈建议不要依赖此功能。
    • /e 将不再适用于 PHP 7 php.net/manual/en/…
    【解决方案4】:

    一个完整的解决方案不会比这更简单/更容易阅读......

    代码:https://3v4l.org/rrXP7

    $str = 'JAMES "JIMMY" SMITH';
    echo ucwords(strtolower($str), ' "');
    

    输出:

    James "Jimmy" Smith
    

    这只是在ucwords() 调用中将双引号和空格声明为分隔符的问题。

    【讨论】:

      【解决方案5】:

      这样的事情可能会奏效:

      preg_replace("/(\w+)/e", "ucwords(strtolower('$1'))", $proper_str);
      

      【讨论】:

        【解决方案6】:

        作为我的自定义 ucwords() 函数的一部分,我在不使用正则表达式的情况下执行此操作。假设字符串中出现的引号不超过两个:

        $parts = explode('"', $string, 3); 
        if(isset($parts[2])) $string = $parts[0].'"'.ucfirst($parts[1]).'"'.ucfirst($parts[2]);            
        else if(isset($parts[1])) $string = $parts[0].'"'.ucfirst($parts[1]);   
        

        【讨论】:

          【解决方案7】:

          你应该这样做:

          $proper_str = 
              preg_replace_callback(
                  '/"([a-z])/',
                  function($m){return strtoupper($m[1]);},
                  $proper_str
          );
          

          出于安全原因,您不应该使用“eval()”。

          无论如何,不​​推荐使用模式修饰符“e”。 请参阅:PHP Documentation

          【讨论】:

            【解决方案8】:
            echo ucwords(mb_strtolower('JAMES "JIMMY" SMITH', 'UTF-8'), ' "'); // James "Jimmy" Smith
            

            ucwords() 有第二个 delimiter 参数,可选的 delimiters 包含单词分隔符。使用空格 ' ' 和 " 作为分隔符,“Jimmy”将被正确识别。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-11-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-08-08
              • 2022-01-23
              相关资源
              最近更新 更多