从字符串中删除连续重复的单词

6

我想从字符串中删除重复的词(仅连续的)。

$str = 'abc,def,fgh,fgh,xna,fgh,xyz,xyz,xyz,tr,tr,xna';

我期望的输出字符串是:

abc,def,fgh,xna,fgh,xyz,tr,xna

我可以使用以下代码在php中获得我想要的结果:
$ip = explode(',', $str);
$op = [];$last = null;
for($i=0;$i<count($ip);$i++){
    if ($last == $ip[$i]) {
        continue;
    }
    $op[]=$last=$ip[$i];
}
$ip = implode(',', $op);

但我希望使用正则表达式的方法。到目前为止,我已经用这两个正则表达式接近了:

$after = preg_replace('/(?:^|,)([^,]+)(?=.*,\1(?:,|$))/m', '', $str);
output : abc,def,fgh,xyz,tr,xna

$after = preg_replace('/([^,]+)(,[ ]*\1)+/m', '', $str);
output : abc,degh,fgh,xna,fgh,,,xna
5个回答

2
$after = preg_replace('/(?<=^|,)([^,]+)(,\s*\1)+/', '$1', $str);

顺便说一句,如果在,之后没有期望的空格,您可以从上面的正则表达式中去掉\s*。我只是看了你的[ ]*,猜想你可能有空格。


抱歉,由于我之前没有正确复制这个正则表达式,导致您的解决方案出现错误输出。 - Progrock

2

You should use

preg_replace('~(?<![^,])([^,]+)(?:,\1)+(?![^,])~', '$1', $str)

请查看正则表达式演示
如果需要支持逗号和重复值之间的任意0个或多个空格字符,\1之前添加\s*(0个或多个空格)模式。 详细信息
  • (?<![^,]) - 字符串开头或除逗号外的任何字符
  • ([^,]+) - 第一组:除逗号外的任何一个或多个字符
  • (?:,\1)+ - 一个或多个由逗号和第一组中的值组成的序列
  • (?![^,]) - 字符串结尾或除逗号外的任何字符。

"Original Answer"翻译成"最初的回答"

1
@Progrock 这个表达式不是自动生成的,关键在于:1)你需要一个起始边界,2)捕获组内的重复模式,3)一个带有分隔符和对第一组的反向引用的组,该组应重复1次或多次,然后4)一个尾部边界。如果没有边界,Group 1中捕获的值的一部分可能会被错误地匹配。 - Wiktor Stribiżew

1
我会这样解决它:

$after = preg_replace('/(?<=,|^)([^,]+)\K(,\1)+(?=,|$)/', '', $str);

这将输出abc,def,fgh,xna,fgh,xyz,tr,xna
它的作用是:
  • (?<=,|^) 查看逗号或字符串开始是否在其前面
  • ([^,]+) 匹配除逗号以外的任何内容(搜索模式)
  • \K 重置内部光标并“忘记”之前的内容(例如,它不会计算更长的匹配项)
  • (,\1)+ 匹配第一个定义的搜索模式的多个出现
  • (?=,|$) 查看下一个字符是否再次为逗号或字符串是否结束
因此,想法是选择任何模式的重复项(仅重复项)并用空白替换它们。 更新: 通过添加(?=,|$)修正了该模式。否则,此测试输入将失败并完全删除xna部分。
$str = 'bc,abc,abc,abc,def,fgh,fgh,xna,fgh,xyz,xyz,xyz,tr,tr,xna,xna,xnabc';

在这里测试:https://regex101.com/r/Yv1htV/3


1

使用strtok进行迭代,只粘合与上一个不同的部分:

<?php

$str = 'abc,def,fgh,fgh,xna,fgh,xyz,xyz,xyz,tr,tr,xna';

$out = $last = strtok($str, ',');
while($current = strtok(','))
    if($current !== $last)
        $out .= ',' . ($last = $current);

echo $out;

输出:

abc,def,fgh,xna,fgh,xyz,tr,xna

1
使用 `array_reduce` 函数:
$arr = explode(',', $str);
$prev = array_shift($arr);
$result = array_reduce($arr, function($c, $i) use (&$prev) {
    if ($prev==$i) return $c;
    $prev=$i;
    return "$c,$i";
}, $prev);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接