我需要帮助来改进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] => !!!
)
)
请帮助。
答案 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] => !
)
)