c# - 如何使用 C# 在文本中查找重复出现的词组?

标签 c# regex text

关闭。这个问题需要更多focused .它目前不接受答案。












想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .

5年前关闭。




Improve this question




我在 StringBuilder(sb) 中使用我在互联网上找到的这段代码获得了重复出现的字数统计,据作者说,它与 Word 的字数计数器非常一致。

StringBuilder wordBuffer = new StringBuilder();
        int wordCount = 0;
        // 1. Build the list of words used. Consider ''' (apostrophe) and '-' (hyphen) a word continuation character.
        Dictionary<string, int> wordList = new Dictionary<string, int>();
        foreach (char c in sb.ToString())
        {

            if (char.IsLetter(c) || c == '\'' || c == '-')
            {
                wordBuffer.Append(char.ToLower(c));
            }
            else
            {
                if (wordBuffer.Length > 3)
                {
                    int count = 0;
                    string word = wordBuffer.ToString();
                    wordList.TryGetValue(word, out count);
                    wordList[word] = ++count;

                    wordBuffer.Clear();
                    wordCount++;
                }
            }
        }

这是我的示例文本:

The green algae (singular: green alga) are a large, informal grouping of algae consisting of the Chlorophyte and Charophyte algae, which are now placed in separate Divisions. The land plants or Embryophytes (higher plants) are thought to have emerged from the Charophytes.[1] As the embryophytes are not algae, and are therefore excluded, green algae are a paraphyletic group. However, the clade that includes both green algae and embryophytes is monophyletic and is referred to as the clade Viridiplantae and as the kingdom Plantae. The green algae include unicellular and colonial flagellates, most with two flagella per cell, as well as various colonial, coccoid and filamentous forms, and macroscopic, multicellular seaweeds. In the Charales, the closest relatives of higher plants, full cellular differentiation of tissues occurs. There are about 8,000 species of green algae.[2] Many species live most of their lives as single cells, while other species form coenobia (colonies), long filaments, or highly differentiated macroscopic seaweeds. A few other organisms rely on green algae to conduct photosynthesis for them. The chloroplasts in euglenids and chlorarachniophytes were acquired from ingested green algae,[1] and in the latter retain a nucleomorph (vestigial nucleus). Green algae are also found symbiotically in the ciliate Paramecium, and in Hydra viridissima and in flatworms. Some species of green algae, particularly of genera Trebouxia of the class Trebouxiophyceae and Trentepohlia (class Ulvophyceae), can be found in symbiotic associations with fungi to form lichens. In general the fungal species that partner in lichens cannot live on their own, while the algal species is often found living in nature without the fungus. Trentepohlia is a filamentous green alga that can live independently on humid soil, rocks or tree bark or form the photosymbiont in lichens of the family Graphidaceae.



通过我的示例文本,我得到了 绿色藻类正如预期的那样,第一行中的单词。

问题是 ,我不仅需要单个词,我也需要词组。对于这个示例文本,我想要 绿藻词也一样,连同 绿色藻类字。

我的可选问题是:我需要以高性能来完成它,因为文本可能很长。正如我研究的那样,在这种情况下使用 RegEx 的性能并不高,但我不确定是否有第二种方法可以实现。

提前致谢。

更新 如果您明白我要问的内容,则无需阅读这些行。
由于我看到太多关于我的“组”定义的评论并不清楚,我想我需要更详细地陈述我的观点,我希望在评论部分写下这些行,但这次更新的范围有点窄。首先,我知道 StackOverflow 不是编码服务。我试图找到一篇文章中最常用的词组,并试图确定文章的内容,我们也可以称之为标签生成器。为此,我试图找到最常用的词,一开始没问题。然后我意识到这不是决定主题的好方法,因为我不能假设这篇文章只有第一个或第二个词。在我的例子中,我不能说这篇文章只是关于 绿色藻类因为他们在这里意味着某种意义,而不是单独存在。如果我用一篇关于像“Helena Bonham Carter”这样的三位名人的文章来尝试这个(如果我假设它在文章中写的是全名,而不仅仅是姓氏),我想把这些词放在一起,而不是一个一个。我正在尝试实现更聪明的算法,该算法以最准确的方式并一次性猜测主题。我不想限制字数,因为文章可能是关于“联合国工业发展组织”(我再次假设它现在写成文章中的“UNIDO”)。我可以通过尝试让每个词组从任何索引开始到任何长度的文本结尾来实现这一点。好吧,这真的不是一个好方法,尤其是长文本,但这并非不可能,对吗?但是我正在寻找一种更好的方法来做到这一点,我只是询问了更好的算法思想和最佳使用工具,我可以自己编写代码。我希望我最终明确了我的目标。

最佳答案

实现此目的的方法是获取初始文本,并使用 string.split(' '); 将其按空格拆分为字符串数组。

接下来,您需要遍历数组中的每个字符串。
这对于单个单词很容易,但对于组则更复杂。
因此,您需要定义组大小。您必须控制每次迭代时指针前进的数组中的位置数。

一旦您能够迭代数组,您就需要获取单词组(无论您选择了多长时间),并将其存储在某处。
示例中的字典是一个很好的方法。

如果字典包含词组,则将其值加一。
如果它不包含该组,只需将其添加为默认值 1。

 if (wordList.ContainsKey(theKey)) {
   wordList[theKey]++;
 } else {
   wordList.Add(theKey, 1);
 }

您确实正确地提到了您的研究表明正则表达式的性能不高。对于这项任务,正则表达式完全是错误的工具——您不是在寻找模式,而是在检查组。
为此,您必须从头到尾浏览文本,检查值。

任何涉及遍历文本并在其上运行重复函数的任务都不应使用正则表达式。

编辑:我对 Regex 性能的最初假设是不正确的 - 在 C# 中,它似乎比在 Java 中快得多,但我仍然认为纯正则表达式方法不如使用正则表达式标记文本快然后使用循环或 linq 表达式来查找组。

陈述

@galakt As I mentioned above, let's say 3. Does it matter?



词组的概念是完全抽象的。是的,它是一组单词,但整个文本块是一组单词。
必须应用规则来管理您如何处理该组词。

下面是一个示例方法,它将根据通过方法调用传递的大小返回所有单词组的字典。
它不会从文本中去除任何非字母数字字符,但速度很快,即使组大小较大。

要调用它,请使用 Dictionary<String, int> SingleWordGroups = GetWordGroupInstances(1);
    private Dictionary<String, int> GetWordGroupInstances(int GroupSize) {

        Dictionary<String, int> WordGroupInstances = new Dictionary<string, int>();

        //Grab the string to work from...
        String[] sourceText = GetSourceText().Split(' ');
        int pointer = 0;
        StringBuilder groupBuilder = new StringBuilder();
        while (pointer < sourceText.Length - GroupSize) {
            groupBuilder.Clear();
            int offset = pointer + GroupSize;
            for (int i = pointer; i < offset; i++) {
                //prepend a space to allow separation between words in groups. 
                //We can make a substring from this later starting from char 1 
                //to lose the initial whitespace from the string.
                groupBuilder.Append(" ").Append(sourceText[i]);
            }

            String key = groupBuilder.ToString().Substring(1);
            if (!WordGroupInstances.ContainsKey(key)) {
                WordGroupInstances.Add(key, 1);
            } else {
                WordGroupInstances[key]++;
            }

            /**
             * Setting the pointer to increase by group size grabs a group, moves on
             * to the end of the group, and grabs the next.
             * 
             */
            pointer += GroupSize;

            /**
             * Setting the point to increment by 1 grabs a group, advances by 1 word, then
             * grabs the next, so from the phrase - "Hello world, I'm some text", the groups of size 2 would be
             * "Hello world,", "world, I'm", "I'm some" etc...
             */
            //pointer++;
        }

        return WordGroupInstances;

    }

下面的方法修改为依次产生所有的组输出,所以

绿色的
绿藻
绿藻
等等...

值得注意的是,整个文本必须转换为小写或大写,以便单词不依赖于大小写。
我对它进行了一些改进以提高性能(并消除对 break 指令的需要)。
   private Dictionary<String, int> GetAllGroups() {
        Dictionary<string, int> WordGroupInstances = new Dictionary<string, int>();
        StringBuilder groupBuilder = new StringBuilder();
        String[] sourceText = GetSourceText().Split(' ');

        for (int i = 0; i < sourceText.Length; i++) {
            groupBuilder.Clear();
            for (int j = i; j < sourceText.Length; j++) {
                groupBuilder.Append(" ").Append(sourceText[j]);
                String key = groupBuilder.ToString().Substring(1);
                if (!WordGroupInstances.ContainsKey(key)) {
                    WordGroupInstances.Add(key, 1);
                } else {
                    WordGroupInstances[key]++;
                }
            }
        }
        return WordGroupInstances;
    }

使用文本语料(288个词)进行性能测试后,将在0.171886秒内创建41773个词组。

关于c# - 如何使用 C# 在文本中查找重复出现的词组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33886103/

相关文章:

c# - 如何将 Redis 与 ElasticSearch 结合使用

c# - 停止 Kestrel 服务器接受来自代码的请求

c# - 为什么 CameraCaptureUI 总是显示圆形裁剪?

c# - 没有 Getter/Setter 的反射?

c++ - 如何使用正则表达式 C++?

C printf 函数无法正确对齐包含土耳其字符的字符串

javascript - 有没有办法在 javascript 中向文本节点添加属性?

javascript - 正则表达式过滤掉某些字符

javascript - 如何生成保留标点符号的简单字谜?

ios - 如何存储大量的游戏对话