使用c#和Regex查找并包围一些html文本中的所有单词和数字

本文关键字:文本 数字 单词 html Regex 查找 包围 使用 | 更新日期: 2023-09-27 18:14:55

我需要在加载的html文本中包含一个span,该span将唯一标识每个单词。问题是有些内容没有被我的正则表达式模式处理。我目前的问题包括…

1)特殊的html字符如” “被视为单词。

2)货币价值。例如2500美元最终成为"2"500"(我需要"2500美元")

3)双连字符的单词。例如one-legged-man。最后变成"独腿"人"

我是正则表达式的新手,在看了其他各种帖子之后,得出了以下模式,除了上述例外情况外,它似乎适用于所有事情。目前我得到的是:

string pattern = @"(?<!<[^>]*?)'b(''w+)|('w+['-]'w+)|('w+')|('w+)'b(?![^<]*?>)";
string newText = Regex.Replace(oldText, pattern, delegate(Match m) {
                  wordCnt++;
                  return "<span data-wordno='" + wordCnt.ToString() + "'>" + m.Value + "</span>";
 });

我如何修复/扩展上述模式以满足这些问题,或者我应该一起使用不同的方法?

使用c#和Regex查找并包围一些html文本中的所有单词和数字

你在这里遇到的一个基本问题是html不是一种"常规语言"。这意味着html足够复杂,您总是能够提出任何正则表达式都无法识别的有效html。这不是写一个更好的正则表达式的问题;这是一个正则表达式无法解决的问题。

你需要的是一个专门的html解析器。你可以试试这个包。还有很多其他的,但是htmllagilitypack是非常流行的。

编辑:下面是一个使用htmllagilitypack的示例程序。解析HTML文档时,结果是一个树(即DOM)。在DOM中,文本存储在文本节点中。因此,像<p>Hello World<'p>这样的东西被解析成一个节点来表示p标记,用一个子文本节点来保存"Hello World"。因此,您要做的是找到文档中的所有文本节点,然后,对于每个节点,将文本分成单词,并用span将单词括起来。

可以使用xpath查询搜索所有文本节点。我下面的xpath是/html/body//*[not(self::script)]/text(),它避免了html头部和正文中的任何脚本标记。

class Program
{
    static void Main(string[] args)
    {
        var doc = new HtmlDocument();
        doc.Load(args[0]);
        var wordCount = 0;
        var nodes = doc.DocumentNode
                       .SelectNodes("/html/body//*[not(self::script)]/text()");
        foreach (var node in nodes)
        {
            var words = node.InnerHtml.Split(' ');
            var surroundedWords = words.Select(word =>
            {
                if (String.IsNullOrWhiteSpace(word))
                {
                    return word;
                }
                else
                {
                    return $"<span data-wordno={wordCount++}>{word}</span>";
                }
            });
            var newInnerHtml = String.Join("", surroundedWords);
            node.InnerHtml = newInnerHtml;
        }
        WriteLine(doc.DocumentNode.InnerHtml);
    }
}

修复1)通过添加"负向后看断言" (?<!'&)。我相信在上述原始模式的第1、第3和第4个选项的开头需要它们。

通过在pattern的末尾添加一个新的替代|('$?('d+[,.])+'d+)'来修复2)。这也可以同时处理非美元数和小数。

修复3)通过将('w+['-]'w+)选项增强为read代替(('w+['-])+'w+)