消除字符串中的冗余字母? (例如gooooooooood - > good)

时间:2011-09-24 21:08:45

标签: c# regex

我正在尝试为Twitter的朴素贝叶斯分类器设置一些示例数据。

我想做的推文的一个后期处理是删除不必要的重复字符。

例如,其中一条推文内容为:Twizzlers. mmmmm goooooooooooood!

我想将w的数量减少到只有两个。为什么两个?这就是我正在关注的文章。丢弃任何小于2个字符的单个单词(参见上面的mmmmm)。对于gooooooood,我认为双字母是最常见的重复。

那么,那就是说,将gooooooooood这样的单词简化为好的最快方式(就执行时间而言)是什么?

[编辑] 我将在这个应用程序中处理800,000条推文,因此需要最快的执行速度 [/编辑]

[EDIT2] 我只是根据经过的时间运行了一些简单的基准测试来迭代1000条记录&保存到文本文件。我在每个方法上重复了这次迭代100次。平均结果如下:

方法1:386 ms [LINQ - 答案已删除] 方法2:407毫秒[正则表达式] 方法3:303 ms [StringBuilder] 方法4:301 ms [StringBuilder第2部分]

方法1:LINQ(答案显然已删除)

static string doIt(string a)
    {
        var l = a.Select((p, i) => new { ch = p, index = i }).
            Where(p => (p.index < a.Length - 2) && (a[p.index + 1] == p.ch) && (a[p.index + 2] == p.ch))
            .Select(p => p.index).ToList();
        l.Sort();
        l.Reverse();

        l.ForEach(i => a = a.Remove(i, 1));

        return a;
    }

方法2:

Regex.Replace(tweet,@"(\S)\1{2,}","$1$1");

方法3:

static string StringB(string s)
    {
        string input = s;
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < input.Length; i++)
        {
            if (i < 2 || input[i] != input[i - 1] || input[i] != input[i - 2])
                sb.Append(input[i]);
        }
        string output = sb.ToString();
        return output;

    }

方法4:

static string sb2(string s)
    {
        string input = s;

        var sb = new StringBuilder(input);

        char p2 = '\0';
        char p1 = '\0';

        int pos = 0, len = sb.Length;
        while (pos < len)
        {
            if (p2 == p1) for (; pos < len && (sb[pos] == p2); len--)
                    sb.Remove(pos, 1);

            if (pos < len)
            {
                p2 = p1;
                p1 = sb[pos];
                pos++;
            }
        }
        return sb.ToString();

    }

4 个答案:

答案 0 :(得分:2)

这也可以通过正则表达式轻松实现:

var re = @"((.)\2)\2*";
Regex.Replace("god", re, "$1")    // god
Regex.Replace("good", re, "$1")   // good
Regex.Replace("gooood", re, "$1") // good

它比其他方法更快吗?好吧,这是基准测试;-)正则表达式在非简并回溯情况下非常有效。上面的内容可能需要更改(例如,这也会匹配空格),但这只是一个小例子。

快乐的编码。

答案 1 :(得分:2)

Regexen看起来是最简单的。 REPL中的简单概念证明:

using System.Text.RegularExpressions;  
var regex = new Regex(@"(\S)\1{2,}"); // or @"([aeiouy])\1{2,}" etc?
regex.Replace("mmmmm gooood griieeeeefff", "$1$1");

- &GT;

"mm good griieeff"

对于原始效果,请使用以下内容:https://ideone.com/uWG68上查看

using System;
using System.Text;

class Program
{
    public static void Main(string[] args)
    {
        string input = "mmmm gooood griiiiiiiiiieeeeeeefffff";

        var sb = new StringBuilder(input);

        char p2 = '\0';
        char p1 = '\0';

        int pos = 0, len=sb.Length;
        while (pos < len)
        {
            if (p2==p1) for (; pos<len && (sb[pos]==p2); len--)
                sb.Remove(pos, 1);

            if (pos<len)
            {
                p2=p1;
                p1=sb[pos];
                pos++;
            }
        }

        Console.WriteLine(sb);
    }
}

答案 2 :(得分:1)

我同意这些评论,这在一般情况下不起作用,特别是在“Twitter发言”中。说过你提到的规则很简单 - 删除与前两个字符相同的每个字符:

string input = "goooooooooooood";
StringBuilder sb = new StringBuilder(input.Length);
sb.Append(input.Substring(0, 2));

for (int i = 2; i < input.Length; i++)
{
    if (input[i] != input[i - 1] || input[i] != input[i - 2])
        sb.Append(input[i]);
}
string output = sb.ToString();

答案 3 :(得分:1)

我建议调查NLP解决方案而不是C#/ regex。在那个世界里,python是首选。见NLTK。我建议Nodebox Linguistics给你拼写修正。你甚至可以干掉单词,甚至可以归结为不定式。