如何从字符串中删除重复的字符

11
我有一个网站,允许用户对照片发表评论。当然,用户会留下如下评论:

'OMGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG!!!!!!!!!!!!!!!'

或者

'YOU SUCCCCCCCCCCCCCCCCCKKKKKKKKKKKKKKKKKK'

你懂的。
基本上,我想通过删除至少大部分多余重复字符来缩短这些评论。我相信可以用正则表达式实现......我只是想不出怎么做。
有什么想法吗?

5
我认为这不是一个好的解决方案……这会改变评论的语言学特征,使作者所意图的愚蠢变成了胡言乱语。基本上他们想表达的是愚蠢,但你会将其转化为无意义的话。例如,当有人说“咕——!”时,你会把它变成“咕!”吗?数字、用户名、网址呢? - tenfour
4
你最好从重复的字母开始缩短-英语中双字母过于常见。 - Piskvor left the building
1
良好类型化的愚蠢垃圾邮件仍然是愚蠢的垃圾邮件,只是稍微难以一眼识别。 - Mark Pim
2
这里还可以查看一个典型的例子,说明为什么这种做法可能不是一个好主意:http://www.codinghorror.com/blog/2008/10/obscenity-filters-bad-idea-or-incredibly-intercoursing-bad-idea.html - Mark Pim
2
你会允许多少个重复字符(例如“you suucckk”与“you sssuuuccckkk”或“you ssssuuuucccckkkk”)?或者像“LOLOLOLOLOLOLOLOLOL”或“s s s s s u u u u c c c c k k k k”这样的重复字符簇呢? - Juliet
显示剩余2条评论
7个回答

10

牢记英语经常使用双字母,你可能不想盲目消除它们。这是一个正则表达式,将除了双字母以外的任何东西都清除掉。

Regex r = new Regex("(.)(?<=\\1\\1\\1)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);

var x = r.Replace("YOU SUCCCCCCCCCCCCCCCCCKKKKKKKKKKKKKKKKKK", String.Empty);
// x = "YOU SUCCKK"

var y = r.Replace("OMGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG!!!!!!!!!!!!!!!", String.Empty);
// y = "OMGG!!"

俄语有时会使用三个字母(非常少),仅供参考。 - AgentFire
有趣,我不知道这一点。如果能够增强正则表达式以了解预期重复两次或三次的字母集,并相应地进行操作,那将是很酷的。 - Ryan Pedersen
它没有回答问题,你的版本会留下双倍。 - HamsterWithPitchfork
@metabuddy 仔细阅读问题。要求删除大部分重复内容。根据提供的答案,您应该能够进行必要的调整以删除所有重复项。 - Ryan Pedersen

9
您是否想要在代码中缩短字符串,或者简单地验证失败并再次向用户呈现带有验证错误的表单就足够了?例如“太多重复字符”。
如果后者可行,@"(\w)\1{2}"应该匹配三个或更多个字符(被解释为“重复”两次或更多次)。 编辑:正如@Piskvor指出的那样,这将匹配恰好3个字符。它适用于匹配,但不适用于替换。他的版本@"(\w)\1{2,}"对于替换更有效。然而,我想指出的是,在此处替换不是最佳实践。最好让表单未通过验证,而不是试图清理提交的文本,因为可能会出现边缘情况,使得原本可读(即使不合理)的文本变成无意义的。

1
我会说这是 (\w)\1{2,}。而 (\w)\1{2} 只会匹配三个字符。 - Piskvor left the building
@Piskvor:你确定吗?我并不是正则表达式专家,但我刚在“abbbbbbbcdef”上测试了一下我的正则表达式,它匹配了。(至少在.NET中,这可能甚至展示了非标准行为,但这是相关环境。) - David
哦,它会匹配(因为有恰好三个重复的子字符串),但它不会匹配整个重复部分 - 请注意,它仅匹配粗体部分:“a bbb bbbbcdef”。它只是不太方便进行匹配和替换。 - Piskvor left the building
@Piskvor:啊,现在我明白你的观点了。尽管我认为自动替换并不是解决问题的方式。(你上面的评论很好地说明了这种方法的一个危险性)。最好的做法可能是将表单退回给用户作为无效提交。 - David
@David:啊,说得好 - 但我不会只匹配三个字符,因为我可以想象出它们是有效的情况(“动物学”?也许不是。“微软办公 vs 开源办公”?也许是)。也许需要更复杂的检查? - Piskvor left the building
1
@Piskvor:同意。这是一个快速简便的潜在滥用检查(需要执行的众多检查之一),但这绝不是完整的解决方案。实际上,这是ROI的问题。如果没有一个稳定的自我维护社区,那么就由网站管理员来确定检测不良输入所需的工作量,并尽力获取最大的开发回报。 - David

1
var nonRepeatedChars = myString.ToCharArray().Distinct().Where(c => !char.IsWhiteSpace(c) || !myString.Contains(c)).ToString();

1

正则表达式有点杀鸡焉用牛刀的感觉。 试试这个:

public static string RemoveRepeatedChars(String input, int maxRepeat)
    {
        if(input.Length==0)return input;

        StringBuilder b = new StringBuilder;
        Char[] chars = input.ToCharArray();
        Char lastChar = chars[0];
        int repeat = 0;
        for(int i=1;i<input.Length;i++){
            if(chars[i]==lastChar && ++repeat<maxRepeat)
            {
                b.Append(chars[i]);
            }
            else
            {
                b.Append(chars[i]);
                repeat=0;
                lastChar = chars[i];
            }
        }
        return b.ToString();
    }

0
var test = "OMMMMMGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGMMM";

test.Distinct().Select(c => c.ToString()).ToList()
        .ForEach(c =>
            { 
                while (test.Contains(c + c)) 
                test = test.Replace(c + c, c); 
            }
        );

0

编辑:糟糕的建议,请不要阅读,我真的应该得到我的-1分:)

我在技术小贴士上找到了类似于你所寻找的东西。

除了一个非常长的正则表达式之外,没有什么可做的,因为我从未听说过有关重复的正则表达式符号...

这只是一个完整的示例,我不会在这里粘贴它,但我认为这完全可以回答你的问题。


1
啊,太可怕了。这只能停止黑名单字符——现在Unicode得到广泛支持后已经没有什么用处了。去读一下正则表达式的反向引用——它们确实存在,尽管你直到现在还从未听说过。 - Piskvor left the building
@Piskvor:是的,我试图寻找它们,但我无法找到解释它们的地方。事实上,在@"(\w)\1{2}"中,我不明白\1代表什么。如果你有一个能解释这个的链接,那对我会非常有用 :) - LaGrandMere
@David 非常感谢您的解释 :) 如果有人有链接,我会非常感激! - LaGrandMere
1
嗯...在那个不可名状的搜索引擎中输入"正则表达式反向引用"给出了"约40,900个结果" - 第一个结果很清楚地解释了它(并且链接到了与提问者所发帖问题相同类型的问题:http://www.regular-expressions.info/duplicatelines.html)。简化版:`(\w)`是第一个捕获组(匹配可以在模式的后面引用),`\1`是对此匹配的引用,`{2}`匹配前面的`\1`恰好2次(应该使用`{2,}`来匹配2次或更多次)。 - Piskvor left the building
@Piskvor:哈哈哈,我有点困惑,对这篇文章的参与很少...我想是时候喝杯咖啡或者...好好睡一觉了!感谢你的解释 :) - LaGrandMere
显示剩余2条评论

0
Distinct()会删除所有重复项,但它不会将"A"和"a"视为相同的,显然。
Console.WriteLine(new string("Asdfasdf".Distinct().ToArray()));

输出 "Asdfa"


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