【问题标题】:Regular expression to find and remove duplicate words正则表达式查找和删除重复的单词
【发布时间】:2009-06-29 14:55:03
【问题描述】:

在C#中使用正则表达式,有没有办法在包含各种单词和符号的字符串中查找和删除重复的单词或符号?

例如

初始字符串:

“我喜欢这里的环境。环境很好。”

所需的字符串:

“我喜欢这里的环境。很好”

已删除重复项:“the”、“environment”、“.”

【问题讨论】:

    标签: c# regex string


    【解决方案1】:

    正如其他人所说,您需要的不仅仅是一个正则表达式来跟踪单词:

    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);
    

    【讨论】:

    • ToUpperInvariant 优于 ToLower,如果你有 lambda,你有 HashSet 代替 Dictionary 其中 Key==Value。否则,+1。
    • 谢谢。使用 ToUpperInvariant 是否有任何性能提升或只是约定?
    • HashSet 构造函数采用可选的 IEqualityComparer,其 Add 方法返回一个布尔值,指示该项目是否已存在于集合中。所以你可以用“var words = new HashSet(StringComparer.OrdinalIgnoreCase);”来实例化你的 HashSet然后将您的代表简化为单行:“return words.Add(m.Value) ? m.Value : string.Empty;”
    • MS 特殊情况 ToUpperInvariant 以提高速度,当然我现在找不到我在哪里看到的。
    • 非常方便地使用 MatchEvaluator 和 Hashset,谢谢。我只是根据我的具体情况调整了正则表达式并遵循了@LukeH 的建议。
    【解决方案2】:

    这似乎对我有用

    (\b\S+\b)(?=.*\1)
    

    这样匹配

    苹果苹果橙 橙色红色 蓝色 绿色橙色 绿色 蓝色 海盗 忍者 牛仔忍者海盗

    【讨论】:

    • 这是不区分大小写的匹配吗?
    • 看起来他想匹配单词的第二个实例,而不是第一个。
    • 也可以试试pirates ninjas cowboys ninjas pirates dallascowboys
    • 好吧,你可以使用后向引用而不是前向引用。(?&lt;=.*\1.*)(\b\S+\b)
    • @chaos -- RegexBuddy 说不匹配。记住,匹配本身就是边界、东西、边界
    【解决方案3】:

    好吧,Jeff 向我展示了如何使用表达式内反向引用和全局修饰符的魔力来实现这一点,所以我最初的答案是无效的。你们都应该投票给杰夫的答案。但是,为了后人,我会注意到在这个问题中存在一个棘手的正则表达式引擎敏感性问题,如果您使用的是 Perl 风格的正则表达式,则需要这样做:

    \b(\S+)\b(?=.*\b\1\b.*)
    

    而不是 Jeff 的答案,因为 C# 的正则表达式将有效地捕获 \1 中的 \b 但 PCRE 不会。

    【讨论】:

    • 我们都曾走过这条路……“有些人在遇到问题时会想‘我知道,我会使用正则表达式。’现在他们有两个问题。”
    • 但是现在有没有不支持任何有状态的正则表达式引擎?这是一个带有反向引用的非常简单的任务。事实上,我认为在 Camel 书(Programming Perl)中使用了类似的东西来演示反向引用。
    • 我告诉你,比赛本身是有界限的。如果您愿意,我可以在 RegexBuddy 中为您截屏并附上一堆测试用例!
    • 我不关心你所说的这个 RegexBuddy。如果它可以在 C# 代码中运行,那么可以,但它在 Perl 中不起作用。
    • 哦,你们这小信。我只是针对生产数据库运行它以删除重复的标签——使用 .NET CLR 正则表达式!也就是说,当然有大量的风味特定问题。当我将 RegexBuddy 切换到“Perl”风格时(它太棒了,它可以让你即时切换引擎),它不匹配。但是OP要求c#,不是吗? :)
    【解决方案4】:

    正则表达式将是解决此问题的“工具”的糟糕选择。也许以下方法可行:

    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
    

    编辑:这是我做了一个很大的假设,即您正在“词法分析”进行某种分析,例如搜索。

    【讨论】:

      【解决方案5】:

      查看反向引用:
      http://msdn.microsoft.com/en-us/library/thwdfzxy(VS.71).aspx

      这是一个可以找到双字的正则表达式。但每次匹配只会匹配一个单词。所以你必须多次使用它。

      new Regex( @"(.*)\b(\w+)\b(.*)(\2)(.*)", RegexOptions.IgnoreCase );
      

      当然,这不是最好的解决方案(请参阅其他答案,其中建议根本不使用正则表达式)。但是你要求一个正则表达式 - 这是一个。也许只是这个想法可以帮助你......

      【讨论】:

        【解决方案6】:

        正则表达式并不适合所有事情。像你的问题确实属于这一类。我建议您改用解析器。

        【讨论】:

          【解决方案7】:

          Some people, when confronted with a problem, think “I know, I'll use regular expressions.” Now they have two problems.

          When not to use Regex in C# (or Java, C++ etc)

          当然,使用正则表达式将字符串拆分为单词可能是有用的第一步,但是 String.Split() 很清楚,它可以轻松完成您需要的一切。

          【讨论】:

            【解决方案8】:

            您将无法使用正则表达式来解决这个问题,因为正则表达式只匹配正则语言。您尝试匹配的模式是上下文相关的,因此不是“常规的”。

            幸运的是,编写解析器很容易。看看 Per Erik Stendahl 的代码。

            【讨论】:

              【解决方案9】:

              正如其他人所指出的,这可以通过反向引用来实现。有关如何在 .Net 中使用反向引用的详细信息,请参阅 http://msdn.microsoft.com/nb-no/library/thwdfzxy(en-us).aspx

              您删除标点符号的特殊问题也使它变得更加复杂,但我认为按照这些行的代码(空格在该正则表达式中并不重要)应该可以解决问题:

              (\b\w+(?:\s+\w+)*)\s+\1
              

              我根本没有测试过正则表达式,但它应该匹配一个或多个由空格分隔且重复的单词。您必须添加更多逻辑以允许标点符号等。

              【讨论】:

                猜你喜欢
                • 2019-01-24
                • 2017-01-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多