我正在尝试为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();
}
答案 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给你拼写修正。你甚至可以干掉单词,甚至可以归结为不定式。