【问题标题】:Regex : how to get words from a string (C#)正则表达式:如何从字符串中获取单词(C#)
【发布时间】:2010-01-29 00:17:13
【问题描述】:

我的输入由用户发布的字符串组成。

我想做的是创建一个包含单词的字典,以及它们的使用频率。 这意味着我想解析一个字符串,删除所有垃圾,并获得一个单词列表作为输出。

例如,假设输入是 "#@!@LOLOLOL YOU'VE BEEN \***PWN3D*** ! :') !!!1einszwei drei !"

我需要的输出是列表:

  • "LOLOLOL"
  • "YOU'VE"
  • "BEEN"
  • "PWN3D"
  • "einszwei"
  • "drei"

我不是正则表达式的英雄,我一直在谷歌上搜索,但我的谷歌功夫接缝很弱……

我将如何从输入到想要的输出?

【问题讨论】:

标签: c# regex string replace


【解决方案1】:

简单的正则表达式:

\w+

这匹配一串“单词”字符。这几乎就是你想要的。

这稍微准确一点:

\w(?<!\d)[\w'-]*

它匹配任意数量的单词字符,确保第一个字符不是数字。

这是我的比赛:

1 大声笑
2 你已经
3 曾
4 PWN3D
5 艾因茨维
6德雷

现在,更像是这样。

编辑:
负面回顾的原因是某些正则表达式支持 Unicode 字符。使用 [a-zA-Z] 会遗漏很多可取的“单词”字符。允许\w 和禁止\d 包括所有可以在任何文本块中以单词开头的Unicode 字符。

编辑 2:
我找到了一种更简洁的方法来获得否定后视的效果:带有单个否定排除的双否定字符类。

[^\W\d][\w'-]*(?<=\w)

这与上面的相同,除了它还确保单词以单词字符结尾。最后,还有:

[^\W\d](\w|[-']{1,2}(?=\w))*

确保一行中的非单词字符不超过两个。 Aka,它匹配“word-up”但不匹配“word--up”,这是有道理的。如果您希望它匹配“word--up”,而不是“word--up”,您可以将 2 更改为 3。

【讨论】:

  • @Led:您可能想在编辑 #2 结束时查看正则表达式。它可能更接近您正在寻找的内容。
  • 投反对票。带有' 符号的单词被分成几部分
【解决方案2】:

您应该研究自然语言处理 (NLP),而不是正则表达式,如果您的目标是不止一种口语,您也需要将其考虑在内。由于您使用的是 C#,请查看 SharpNLP 项目。

编辑:仅当您关心要拆分的单词的语义内容时,才需要这种方法。

【讨论】:

  • 非常感谢您的回复! :) 但是让我们保持简单,并说我不关心语言 - - 我只会考虑带有可选 ''' 和/或 '-' 字符的单词?
  • 如果你不关心语言,那为什么不把你不需要的所有字符 string.Replace() 然后 string.Split() 放在空格字符上呢?不需要正则表达式。
  • @Mike - 哈这就是我刚才的建议
  • 因为指定我 DO 允许的内容似乎更自然:带有可选 ' 或 - 字符的单词,仅此而已。如果我以错误的方式解决这个问题,请告诉我,因为这些东西对我来说有点新;)
  • “给猫剥皮的方法不止一种。”
【解决方案3】:

如果您正在做的只是标记化,那么您不一定需要正则表达式。首先,您可以通过删除除空格以外的所有非字母字符来清理字符串,然后对空格字符执行Split()。这对大多数事情都有效,尽管宫缩可能很艰难。这至少应该让你开始。

【讨论】:

  • 好的,所以我想做的是删除所有无效字符,但如果 ' 和 - 字符不在字母字符之间,它们也是无效的。 (在“word-up”中 - 是有效的,在“word ----- up”中 - 字符应该被删除......)
  • 您可以在其中进行检查,查看' 或- 是否被字母字符包围,如果是,请不要删除。
【解决方案4】:

使用以下

var pattern = new Regex(
  @"( [^\W_\d]              # starting with a letter
                            # followed by a run of either...
      ( [^\W_\d] |          #   more letters or
        [-'\d](?=[^\W_\d])  #   ', -, or digit followed by a letter
      )*
      [^\W_\d]              # and finishing with a letter
    )",
  RegexOptions.IgnorePatternWhitespace);

var input = "#@!@LOLOLOL YOU'VE BEEN *PWN3D* ! :') !!!1einszwei drei foo--bar!";

foreach (Match m in pattern.Matches(input))
  Console.WriteLine("[{0}]", m.Groups[1].Value);

产生输出

[大声笑]
[你已经]
[到过]
[PWN3D]
[einszwei]
[德雷]
[富]
[条]

【讨论】:

  • 你能正常写一个正则表达式吗?我的意思是没有多余字符的单行
  • 很好的解释。
【解决方案5】:

我的直觉不会是使用正则表达式,而是做一两个循环。

遍历字符串中的每个字符,如果不是有效字符,则将其替换为空格 然后使用 String.Split() 分割空格。

撇号和连字符可能有点难以确定它们是垃圾字符还是合法字符。但是,如果您使用 for 循环遍历字符串,那么从当前字符向后和向前看应该会对您有所帮助。

然后您将获得一个单词列表 - 为每个单词检查它们在您的字典中是否有效。如果您希望它更快,最好执行某种二进制搜索。但是为了让它工作,线性搜索会更容易开始。

编辑:我只提到字典是因为我认为您可能只对合法词感兴趣,即不是“asdfasdf”,但如果这不是您需要的,请忽略最后一条语句。

【讨论】:

  • 您不想用空格替换无效字符。
【解决方案6】:

我为这样的字符串写了一个扩展:

    private static string[] GetWords(string text)
    {
        List<string> lstreturn = new List<string>();
        List<string> lst = text.Split(new[] { ' ' }).ToList();
        foreach (string str in lst)
        {
            if (str.Trim() == "")
            {
                lstreturn.Add(str);
            }
        }
        return lstreturn.ToArray();
    }

【讨论】:

  • 这对我来说似乎不是一个扩展。你错过了this吗?
猜你喜欢
  • 2017-12-17
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 2011-12-13
  • 2016-02-24
  • 1970-01-01
  • 2018-05-10
  • 2017-08-09
相关资源
最近更新 更多