【问题标题】:PHP - Improve text capitalization functionPHP - 改进文本大写功能
【发布时间】:2015-03-31 10:35:05
【问题描述】:

我有一个大写字符串的函数:

function capitalize_sentence($text)
    {
      $output =  preg_replace_callback('/([.!?])\s*(\w)/', function ($matches) {
            return strtoupper($matches[1] . ' ' . $matches[2]);
        }, ucfirst(strtolower($text)));
        return $output;
    }

当我有这样一个简单的字符串时:

$text = 'hello. this works !';
var_dump($text);

$text = capitalize_sentence($text);
var_dump($text);die;

这很好用:

string 'hello.this works !' (length=18) 

string 'Hello. This works !' (length=19)

但在我的代码中,有时,字符串看起来像这样(带有一些标签):

$text = '<span>hello.</span> this <b>works</b> !';
var_dump($text);

$text = capitalize_sentence($text);
var_dump($text);die;

这给了我这个(如您所见,第一个单词没有大写...):

string '<span>hello.</span> this <b>works</b> !' (length=39)

string '<span>hello.</span> this <b>works</b> !' (length=39)

如何改进我的代码?我需要在不删除它们的情况下“转义”&lt;tags&gt;,但要像第一个示例一样大写第一个单词....

我需要这样的输出:

string '<span>Hello.</span> This <b>works</b> !' (length=39)

谢谢!

【问题讨论】:

  • 你的预期输出是什么?
  • 我认为你不能通过正则表达式来做到这一点。写一个小的词法分析器
  • @AvinashRaj : '你好。有效!'
  • @tutankhamun 怎么做?
  • 请不要忘记提及您的来源。

标签: php regex capitalization


【解决方案1】:

试试这个:

function ucSentence($str) {
    $len = strlen($str);
    $flagNeedUC = TRUE; // start of sentence flag
    $flagTag = FALSE;   // inside tag flag
    $endOfSentence = array('.', '!', '?');
    for ($ix = 0; $ix < $len; $ix += 1) {
        if ($flagTag) {
            if ('>' === $str{$ix}) { // resolve end tag
                $flagTag = FALSE;
            }
        } else {
            if (in_array($str{$ix}, $endOfSentence)) { // resolve end sentence
                $flagNeedUC = TRUE;
            } elseif ('<' === $str{$ix}) { // resolve start tag
                $flagTag = TRUE;
            } elseif (ctype_alpha($str{$ix}) && $flagNeedUC) { // resolve first char after sentence end
                $flagNeedUC = FALSE;
                $str{$ix} = strtoupper($str{$ix});
            }
        }
    }
    return $str;
}
echo ucSentence('<span><b>hello. </b></span> this <b>works</b> !');

它打印&lt;span&gt;&lt;b&gt;Hello. &lt;/b&gt;&lt;/span&gt; This &lt;b&gt;works&lt;/b&gt;

更新 尤其是@w35l3y :)

我添加了传递属性值。它识别出现在野生互联网中的几种形式的属性值: &lt;tag attr="value"&gt;&lt;tag attr='value'&gt;&lt;tag attr=value attr=value&gt;

function ucSentence($str) {
    $len = strlen($str);
    $flagNeedUC = TRUE; // start of sentence flag
    $flagTag = FALSE;   // inside tag flag
    $stageAttr = FALSE;  // inside attribute value
    $endOfSentence = array('.', '!', '?');
    for ($ix = 0; $ix < $len; $ix += 1) {
        if ($flagTag) {
            if ($stageAttr) {
                if ('=' === $stageAttr) {
                    if ('"' === $str{$ix}) {
                        $stageAttr = '"';
                    } elseif ('\'' === $str{$ix}) {
                        $stageAttr = '\'';
                    } else {
                        $stageAttr = ' >';                        
                    }
                } elseif (strpos($stageAttr, $str{$ix}) !== FALSE) {
                    if ('>' === $str{$ix}) {
                        $flagTag = FALSE;
                    }
                    $stageAttr = FALSE;
                }
            } else {
                if ('>' === $str{$ix}) { // resolve end tag
                    $flagTag = FALSE;
                } elseif ('=' === $str{$ix}) {
                    $stageAttr = '=';
                }
            }
        } else {
            if (in_array($str{$ix}, $endOfSentence)) { // resolve end sentence
                $flagNeedUC = TRUE;
            } elseif ('<' === $str{$ix}) { // resolve start tag
                $flagTag = TRUE;
            } elseif (ctype_alpha($str{$ix}) && $flagNeedUC) { // resolve first char after sentence end
                $flagNeedUC = FALSE;
                $str{$ix} = strtoupper($str{$ix});
            }
        }
    }
    return $str;
}

$testArr = array(
    '<span><b>hello. </b></span> this <b>works</b> !',
    'test. <span title="jane <3 john"> <b>hello. </b></span> this <b>works</b> !',
    'test! <span title="hover -> here"> <b>hello. </b></span> this <b>works</b> !',
    'test <span title="jane <3 john"> <b>hello. </b></span> this <b>works</b> !',
    'test? <span title="hover -> here"> <b>hello. </b></span> this <b>works</b> !',
    'test <span title="hover -> here"> <b>hello. </b></span> this <b>works</b> !',
    'test. <span title=\'hover -> here\'> <b>hello. </b></span> this <b>works</b> !',
    'test. <span title=jane<3john data=jane> <b>hello. </b></span> this <b>works</b> !',
);
foreach ($testArr as $num => $testStr) {
    printf("[%d] %s\n", $num, ucSentence($testStr));
}

打印出来:

[0] <span><b>Hello. </b></span> This <b>works</b> !
[1] Test. <span title="jane <3 john"> <b>Hello. </b></span> This <b>works</b> !
[2] Test! <span title="hover -> here"> <b>Hello. </b></span> This <b>works</b> !
[3] Test <span title="jane <3 john"> <b>hello. </b></span> This <b>works</b> !
[4] Test? <span title="hover -> here"> <b>Hello. </b></span> This <b>works</b> !
[5] Test <span title="hover -> here"> <b>hello. </b></span> This <b>works</b> !
[6] Test. <span title='hover -> here'> <b>Hello. </b></span> This <b>works</b> !
[7] Test. <span title=jane<3john data=jane> <b>Hello. </b></span> This <b>works</b> !

【讨论】:

  • @tutankhamun,&lt;span title="jane &lt;3 john"&gt;&lt;b&gt;hello. &lt;/b&gt;&lt;/span&gt; this &lt;b&gt;works&lt;/b&gt; !&lt;span title="hover -&gt; here"&gt;&lt;b&gt;hello. &lt;/b&gt;&lt;/span&gt; this &lt;b&gt;works&lt;/b&gt; ! 呢?
  • 我认为&amp;lt;&amp;gt;必须在HTML中改为&amp;lt;&amp;gt;实体。或者,如果您从狂野的互联网上获得它,您可以在函数调用之前对其进行转义并在函数调用之后取消转义。
  • 嗯。逃避是一种糟糕的方式。标签也会被转义。好的方法是附加条件以围绕属性值。我认为对于非常糟糕的 html i 没有解决方案。 e.&lt;span title=hover -&gt; here&gt;&lt;b&gt;hello. &lt;/b&gt;&lt;/span&gt; 但浏览器也会不喜欢它。
【解决方案2】:

试试这个更新,我添加了更多条件并稍微更改了替换:

 $output =  preg_replace_callback('/((?:^|[.!?])(?:<[^>]*?>)?)(\s*)(\w)/', function ($matches) {
        return $matches[1] . $matches[2] . strtoupper($matches[3]);
    }, ucfirst(strtolower($text)));

它输出&lt;span&gt;Hello.&lt;/span&gt; This &lt;b&gt;works&lt;/b&gt; !

【讨论】:

  • 但我担心正则表达式对于这个问题来说是一个糟糕的解决方案。 '&lt;span&gt;hello. &lt;/span&gt; this &lt;b&gt;works&lt;/b&gt;!'' &lt;span&gt;hello.&lt;/span&gt; &lt;span&gt;this &lt;b&gt;works&lt;/b&gt; &lt;/span&gt;!' 呢?
  • 这显然是对stackoverflow.com/a/5383786/157873 的改进,但我同意@tutankhamun 的观点:stackoverflow.com/questions/5383471/…
【解决方案3】:

这是@tutankhamun 的略微修改版本,可防止电子邮件地址或 URL 中句点后的字符大写(或任何其他时间句尾字符后没有空格 (. ! ?)

function sentenceCase($str) {
    $len = strlen($str);
    $flagNeedUC = TRUE; // start of sentence flag
    $flagTag = FALSE;   // inside tag flag
    $stageAttr = FALSE;  // inside attribute value
    $lastChar = NULL;
    $endOfSentence = array('.', '!', '?');
    for ($ix = 0; $ix < $len; $ix += 1) {
        if ($flagTag) {
            if ($stageAttr) {
                if ('=' === $stageAttr) {
                    if ('"' === $str{$ix}) {
                        $stageAttr = '"';
                    } elseif ('\'' === $str{$ix}) {
                        $stageAttr = '\'';
                    } else {
                        $stageAttr = ' >';
                    }
                } elseif (strpos($stageAttr, $str{$ix}) !== FALSE) {
                    if ('>' === $str{$ix}) {
                        $flagTag = FALSE;
                    }
                    $stageAttr = FALSE;
                }
            } else {
                if ('>' === $str{$ix}) { // resolve end tag
                    $flagTag = FALSE;
                } elseif ('=' === $str{$ix}) {
                    $stageAttr = '=';
                }
            }
        } else {
            if (in_array($str{$ix}, $endOfSentence)) { // resolve end sentence
                $flagNeedUC = TRUE;
            } elseif ('<' === $str{$ix}) { // resolve start tag
                $flagTag = TRUE;
            } elseif (ctype_alpha($str{$ix}) && $flagNeedUC) { // resolve first char after sentence end
                $flagNeedUC = FALSE;
                if (!in_array($lastChar, $endOfSentence)) $str{$ix} = strtoupper($str{$ix});
            }
        }
        $lastChar = $str{$ix};
    }
    return $str;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-28
    • 1970-01-01
    • 2012-01-23
    相关资源
    最近更新 更多