【发布时间】:2009-06-29 14:55:03
【问题描述】:
在C#中使用正则表达式,有没有办法在包含各种单词和符号的字符串中查找和删除重复的单词或符号?
例如
初始字符串:
“我喜欢这里的环境。环境很好。”
所需的字符串:
“我喜欢这里的环境。很好”
已删除重复项:“the”、“environment”、“.”
【问题讨论】:
在C#中使用正则表达式,有没有办法在包含各种单词和符号的字符串中查找和删除重复的单词或符号?
例如
初始字符串:
“我喜欢这里的环境。环境很好。”
所需的字符串:
“我喜欢这里的环境。很好”
已删除重复项:“the”、“environment”、“.”
【问题讨论】:
正如其他人所说,您需要的不仅仅是一个正则表达式来跟踪单词:
var words = new HashSet<string>();
string text = "I like the environment. The environment is good.";
text = Regex.Replace(text, "\\w+", m =>
words.Add(m.Value.ToUpperInvariant())
? m.Value
: String.Empty);
【讨论】:
这似乎对我有用
(\b\S+\b)(?=.*\1)
这样匹配
苹果苹果橙 橙色红色 蓝色 绿色橙色 绿色 蓝色 海盗 忍者 牛仔忍者海盗【讨论】:
pirates ninjas cowboys ninjas pirates dallascowboys。
(?<=.*\1.*)(\b\S+\b)
好吧,Jeff 向我展示了如何使用表达式内反向引用和全局修饰符的魔力来实现这一点,所以我最初的答案是无效的。你们都应该投票给杰夫的答案。但是,为了后人,我会注意到在这个问题中存在一个棘手的正则表达式引擎敏感性问题,如果您使用的是 Perl 风格的正则表达式,则需要这样做:
\b(\S+)\b(?=.*\b\1\b.*)
而不是 Jeff 的答案,因为 C# 的正则表达式将有效地捕获 \1 中的 \b 但 PCRE 不会。
【讨论】:
正则表达式将是解决此问题的“工具”的糟糕选择。也许以下方法可行:
HashSet<string> corpus = new HashSet<string>();
char[] split = new char[] { ' ', '\t', '\r', '\n', '.', ';', ',', ':', ... };
foreach (string line in inputLines)
{
string[] parts = line.Split(split, StringSplitOptions.RemoveEmptyEntries);
foreach (string part in parts)
{
corpus.Add(part.ToUpperInvariant());
}
}
// 'corpus' now contains all of the unique tokens
编辑:这是我做了一个很大的假设,即您正在“词法分析”进行某种分析,例如搜索。
【讨论】:
查看反向引用:
http://msdn.microsoft.com/en-us/library/thwdfzxy(VS.71).aspx
这是一个可以找到双字的正则表达式。但每次匹配只会匹配一个单词。所以你必须多次使用它。
new Regex( @"(.*)\b(\w+)\b(.*)(\2)(.*)", RegexOptions.IgnoreCase );
当然,这不是最好的解决方案(请参阅其他答案,其中建议根本不使用正则表达式)。但是你要求一个正则表达式 - 这是一个。也许只是这个想法可以帮助你......
【讨论】:
正则表达式并不适合所有事情。像你的问题确实属于这一类。我建议您改用解析器。
【讨论】:
见When not to use Regex in C# (or Java, C++ etc)
当然,使用正则表达式将字符串拆分为单词可能是有用的第一步,但是 String.Split() 很清楚,它可以轻松完成您需要的一切。
【讨论】:
您将无法使用正则表达式来解决这个问题,因为正则表达式只匹配正则语言。您尝试匹配的模式是上下文相关的,因此不是“常规的”。
幸运的是,编写解析器很容易。看看 Per Erik Stendahl 的代码。
【讨论】:
正如其他人所指出的,这可以通过反向引用来实现。有关如何在 .Net 中使用反向引用的详细信息,请参阅 http://msdn.microsoft.com/nb-no/library/thwdfzxy(en-us).aspx。
您删除标点符号的特殊问题也使它变得更加复杂,但我认为按照这些行的代码(空格在该正则表达式中并不重要)应该可以解决问题:
(\b\w+(?:\s+\w+)*)\s+\1
我根本没有测试过正则表达式,但它应该匹配一个或多个由空格分隔且重复的单词。您必须添加更多逻辑以允许标点符号等。
【讨论】: