正则表达式将长字符串分隔成短语并存储在数组中

时间:2017-04-17 08:03:45

标签: php regex

我的目的是消除垃圾词并保留一系列有用的短语。 例如。 “我喜欢吃棉花糖,同时也听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”仍然存储在数组中。

1 个答案:

答案 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);

demo

模式细节:

~
(?=\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