我的目的是消除垃圾词并保留一系列有用的短语。 例如。 “我喜欢吃棉花糖,同时也听Metallica'。 我想消除I,to,while。 这反过来会产生一个阵列 0-喜欢 1 - 吃棉花糖 2-听 3- Metallica
我尝试了preg_split并用|分隔每个单词并将每个单词括在括号中
$arr = preg_split("/ (\bwhere\b)| (\bany\b) |(\bfacebook\b)|(\bthe\b)|(\n)|(\r)|(\r\n)|(,) | (\band\b)| (\bundefined\b) /", $bigString);
我遇到的问题: a)如果字符串中的第一个单词在正则表达式中匹配,则它仍然没有被消除。由于某种原因,它仍然保存在字符串中并存储在数组中。 b)有时会忽略连续的比赛。例如。拿字符串'我吃了很多'。尽管正则表达式应该捕获所有4个单词,但单词“a”仍然存储在数组中。
答案 0 :(得分:1)
两个问题(a和b)具有相同的原点,模式中的每个标记都被空格包围。后果:a)当其中一个令牌位于字符串的开头或结尾时,它不起作用。 b)当你的字符串中有连续的标记时它不起作用,因为你不能将相同的空格匹配两次。
无论如何,你构建所有这些单词的替换方法并不好,因为每次在交替中添加新分支时模式性能都会降低(对于字符串中的每个位置,在最坏的情况下,正则表达式引擎需要测试所有分支。)
这就是为什么我建议另一种方法,包括将字符串拆分为例如非字母字符(更准确地说是每个空白字符序列,以及每个非字母和非空字符序列)。完成后,我使用array_diff
删除您不想要的单词。 array_diff
的主要兴趣在于它保留了密钥。这样,您只需在键中找到间隙即可生成结果数组。
即使它看起来更复杂也更长,但这种方式更具可扩展性:
$str = 'I like to eat marshmallows while also listening to Metallica';
$words = [ '',
'also', 'and', 'any',
'I',
'facebook',
'the', 'to',
'where', 'while' ];
$parts = array_diff(preg_split('~(?=\PL)(?:\s+|[^\pL\s]+)~u', $str), $words);
$previousKey = false;
$temp = '';
$result = [];
foreach($parts as $k => $v) {
if ( $previousKey === $k - 1 ) {
$temp .= " $v";
} else {
if ( $previousKey )
$result[] = $temp;
$temp = $v;
}
$previousKey = $k;
}
if ( $previousKey )
$result[] = $temp;
print_r($result);
模式细节:
~
(?=\PL) # improvement trick: make fail quickly positions with a letter
# without to test the whole pattern
(?:
\s+ # any sequence of white-spaces
| # OR
[^\pL\s]+ # any sequence of characters that are not letters or white-spaces
#
# This way: "eat marshmallows" returns:
# [0] => eat marshmallows
# but: "eat, marshmallows" returns:
# [0] => eat
# [1] =>
# [2] => marshmallows
# according to your original pattern
)
~u # make it able to deal with multibyte utf8 strings
更好的模式:~\PL(?(?<=\s)\s*|[^\pL\s]*)~u