PHP正则表达式 - 计算单词前后的感叹号数

时间:2017-01-06 13:50:39

标签: php regex

我需要帮助来改进PHP中的正则表达式,用于计算单词前后出现的感叹号的数量。在这种情况下,单词可以包括除空格之外的任何字符(甚至是感叹号),如下所示(我显示预期的"之前,之后"计数):

!!!!Hi!! => 4, 2
!!!!Hi  => 4, 0
!Hi!!!  => 1, 3
!easdf.kjaf!!  => 1, 2
!hjdfa!sdfk!jaf!!  => 1, 2
!,!!!!!fdgsdfg!!sdgj => 1, 0
!!!,!ksfgfdg!jkft!!!  => 3, 3

如何对正则表达式进行编码,以便在之前,当到达某个非感叹号时,它会停止查找连续的惊叹号,并在只剩下感叹号的情况下开始计数?

棘手的部分是标点符号出现在单词中。这些应该被忽略,这些被认为是这个词的一部分。

我在这里:

 preg_match_all('/(!*)\b(\S+)\b(!*)/', $w, $m);

$ w是单词(如上所示),$ m是匹配数组

作为一个例子," !!嗨!"会导致$ m等于

Array
(
    [0] => Array
        (
            [0] => !!Hi!
        )
    [1] => Array
        (
            [0] => !!
        )
    [2] => Array
        (
            [0] => Hi
        )
    [3] => Array
        (
            [0] => !
        )
)

这是正确的,我正在寻找什么。然而,当标点符号开始或结束单词时,事情就会被抛弃,正则表达式的锚点是#34; \ b"并不认为这是该词的一部分(正如本练习中所定义的那样)。这是一个未能解析单词的示例" !!!!!!!! xd.sfgdx !!!,!!"

Array
(
    [0] => Array
        (
            [0] => !!!!!!!!xd.sfgdx!!!
        )
    [1] => Array
        (
            [0] => !!!!!!!!
        )
    [2] => Array
        (
            [0] => xd.sfgdx
        )
    [3] => Array
        (
            [0] => !!!
        )
)

请帮助。

3 个答案:

答案 0 :(得分:3)

你只需要锚点(^表示开头,$表示结尾),基本上只需要中间的任何东西。对于锚点,如果中间!不在两端,则不会匹配。这可能是第一次尝试;

/^(!*).*(!*)$/

此处中间任何内容(.*)的问题在于它是贪婪的,并且优先于最终的组(!*)。中间的任何东西都会匹配所有的结尾,而这个组合就没有了。虽然很容易修复,但只是让中间人不贪心:

/^(!*).*?(!*)$/

现在它将尽可能地匹配开头的任何!,然后逐步匹配中间的任何内容,直到下一个条件匹配(结尾为!)。

答案 1 :(得分:2)

这是一个快速的非正则表达式解决方案,因为:

$test = ['!!!!Hi!!',
         '!!!!Hi',
         '!Hi!!!',
         '!easdf.kjaf!!',
         '!hjdfa!sdfk!jaf!!',
         '!,!!!!!fdgsdfg!!sdgj',
         '!!!,!ksfgfdg!jkft!!!'];

foreach($test as $str) {
    $count = $rcount = 0;
    for ($i = 0; $i < strlen($str); $i++) {
        if ($str[$i] == '!') {
            $count += 1;
            continue;
        }
        break;
    }

    for ($i = strlen($str) - 1; $i > 0; $i--) {
        if ($str[$i] == '!') {
            $rcount += 1;
            continue;
        }
        break;
    }
    echo $str . ': ' . $count . ', ' . $rcount . '<br />';
}

<强>输出:

!!!!Hi!!: 4, 2
!!!!Hi: 4, 0
!Hi!!!: 1, 3
!easdf.kjaf!!: 1, 2
!hjdfa!sdfk!jaf!!: 1, 2
!,!!!!!fdgsdfg!!sdgj: 1, 0
!!!,!ksfgfdg!jkft!!!: 3, 3

答案 2 :(得分:0)

使用此正则表达式:

preg_match_all('/^(!*)[^!]{1}.*[^!]{1}(!*)/', $w, $m);

对于您的示例输出是:

Array
(
    [0] => Array
        (
            [0] => !!!!Hi!!
        )

    [1] => Array
        (
            [0] => !!!!
        )

    [2] => Array
        (
            [0] => !!
        )

)

Array
(
    [0] => Array
        (
            [0] => !!!,!ksfgfdg!jkft!!,!
        )

    [1] => Array
        (
            [0] => !!!
        )

    [2] => Array
        (
            [0] => !
        )

)