c# - 如何在不匹配其他字符的情况下正确匹配 C# 中的单词分隔符

标签 c# regex string parsing

很抱歉新问题,但 C# 不是我的第一语言。

我正在尝试在给定的内容中为单词之间的所有分隔符建立一个索引列表,并考虑标点符号。我希望使用 Regex\b(单词“边界”),但它匹配我没想到的各种东西。这是我写的方法:

internal static IList<int> GetBreakIndexesInContent(string content)
{
    IList<int> indices = new List<int>();
    if (content != null) 
    {
        foreach (Match match in Regex.Matches(content, @"\b"))
        {
            Console.WriteLine("INDEX:[" + match.Index + "]   CHAR:[" + content.Text[match.Index] + "]   UNICODE:[" + (int)content.Text[match.Index] + "]");
            indices.Add(match.Index);
        }
    }
    return indices;
}

给定以下 100 个字符的字符串:

"Lorem ipsum dolor sit amet, tritani quaestio suscipiantur mea ea, duo et impedit facilisi evertitur."

我期望我的方法生成一个长度为 14 个元素的列表,其中第一个索引将位于位置 5,第二个位置为 11,依此类推(忽略位置 26 和 64 处的逗号,以及位于99).相反,这是我得到的输出:

//COUNT: [30]
INDEX:[0]   CHAR:[L]   UNICODE:[76]
INDEX:[5]   CHAR:[ ]   UNICODE:[32]
INDEX:[6]   CHAR:[i]   UNICODE:[105]
INDEX:[11]   CHAR:[ ]   UNICODE:[32]
INDEX:[12]   CHAR:[d]   UNICODE:[100]
INDEX:[17]   CHAR:[ ]   UNICODE:[32]
INDEX:[18]   CHAR:[s]   UNICODE:[115]
INDEX:[21]   CHAR:[ ]   UNICODE:[32]
INDEX:[22]   CHAR:[a]   UNICODE:[97]
INDEX:[26]   CHAR:[,]   UNICODE:[44]
INDEX:[28]   CHAR:[t]   UNICODE:[116]
INDEX:[35]   CHAR:[ ]   UNICODE:[32]
INDEX:[36]   CHAR:[q]   UNICODE:[113]
INDEX:[44]   CHAR:[ ]   UNICODE:[32]
INDEX:[45]   CHAR:[s]   UNICODE:[115]
INDEX:[57]   CHAR:[ ]   UNICODE:[32]
INDEX:[58]   CHAR:[m]   UNICODE:[109]
INDEX:[61]   CHAR:[ ]   UNICODE:[32]
INDEX:[62]   CHAR:[e]   UNICODE:[101]
INDEX:[64]   CHAR:[,]   UNICODE:[44]
INDEX:[66]   CHAR:[d]   UNICODE:[100]
INDEX:[69]   CHAR:[ ]   UNICODE:[32]
INDEX:[70]   CHAR:[e]   UNICODE:[101]
INDEX:[72]   CHAR:[ ]   UNICODE:[32]
INDEX:[73]   CHAR:[i]   UNICODE:[105]
INDEX:[80]   CHAR:[ ]   UNICODE:[32]
INDEX:[81]   CHAR:[f]   UNICODE:[102]
INDEX:[89]   CHAR:[ ]   UNICODE:[32]
INDEX:[90]   CHAR:[e]   UNICODE:[101]
INDEX:[99]   CHAR:[.]   UNICODE:[46]

我不是简单地尝试匹配 "" 或稍后只是过滤 ASCII 32 的原因是因为这需要对不一定在所有单词之间使用空格的外语敏感.另外,因为我不想无意中将多个空格捕获为单独的“分隔符”。

我真的希望 \b 是真正的单词分离的一个很好的标准包罗万象,但事实似乎并非如此。我可以“自己动手”,但我希望如果 C# 已经有某种设施来处理这个问题,我可以省去重新发明轮子的麻烦。

当然,我们将不胜感激。

谢谢, 格雷格。

最佳答案

如果正则表达式中单词字符的定义 (\w) 满足您的需要(为此,请继续阅读),您可以匹配非单词字符(例如,单词之间的插页式内容通过使用它的反字符类,\W。解决方案可以像

一样简单
private static readonly Regex rxWord = new Regex( @"\w+" ) ;
static IEnumerable<string> ParseWords( string s )
{
  return rxWord.Matches(s).Cast<Match>().Select( m => m.Value ) ;
}

private static Regex rxNonWord = new Regex( @"\W+" ) ;
private static IEnumerable<string> ParseNonWords( string s )
{
  return rxNonWord.Matches(s).Cast<Match>().Select( m => m.Value ) ;
}

但是从你所说的你正在尝试做的事情来看,从 Unicode categories that the CLR supports 组成你的字符类或单词分隔符可能更容易。 .

进一步,使用正则表达式“词”和“非词”类(\w\W)以及它们之间的边界(\b ) 可能不起作用,因为在正则表达式中,“单词”不一定是您认为的那样。字符类 \w 最初是 C 语言标识符 ([A-Za-z0-9_]) 中允许的字符集。如果您是使用正则表达式在源代码中搜索符号的 C 程序员,这将非常有用。不太适合在任意文本中翻找单词。

\w 在 CLR 正则表达式中的当前定义是它匹配包含在这些 Unicode 类别中的任何字符:

  • Li(字母,小写)
  • Lu(字母,大写)
  • Lt(字母,首字母大写)
  • Lo(信件,其他)
  • Lm(字母,修饰符)
  • Nd(数字,十进制数字)
  • Pc(标点符号、连接符)这一类包括10个字符。此处最常见的是 _ (0x005F),又名下划线或 LOWLINE,至少在英语中是这样。

要说的是 \w 是一种懒惰的写法 [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Lm}\p{Nd}\p{Pc}].

非单词字符类 \W 与此相反。这完全等同于 [^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Lm}\p{Nd}\p{Pc}].

零宽度 anchor \b 不“匹配”任何东西:就像它的姐妹 ^$ 一样,\b 锚定匹配到一个特定的地方。在 \b 的情况下,该位置是单词 (\w) 和非单词 (\W) 字符之间的边界. \b 有一个表亲,\B 匹配逆向:它将匹配锚定在两个单词 (\w) 或两个单词之间的边界处非单词 (\W) 字符。

所以...

您需要首先提出适合您的问题领域的“词”定义。这比看起来更难:例如,“二十三”是一两个字吗? “前妻”呢?或者像“抽象表现主义”这样的复合词怎么样,根据上下文是一个或两个词(你会在字典中找到“抽象”、“表现主义”和“抽象表现主义”作为单独的词条)。

如果您可以定义一个符合该定义的字符类,那么一切都很好。要匹配单词之间的间隙内容,您所要做的就是定义其反字符类。

如果一个简单的字符类不适合您,您将需要使用各种前瞻/后视断言来匹配您想要的内容。

关于c# - 如何在不匹配其他字符的情况下正确匹配 C# 中的单词分隔符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19668365/

相关文章:

c++ - C/C++ 中的快速字符串标记化

c# - 使用 C# 正则表达式如何将竖线匹配为文字?

r - dplyr 中的快速字符串计数

javascript - 从 Javascript 中的推文中删除 'RT @name'

python - 如何使用字符或字符串作为放置在操作数之间的运算符?

PHP 如何在复制字符串中的每个字符后将字符串变为 "unduplicate"(还原字符串)

c# - 使用 mongodb 动态创建 linq

C#/MySQL - 从数据库中获取日期

c# - .net 框架的 AddMicrosoftIdentityWebApiAuthentication 模拟

python - 识别给定单词序列前面的字符串