实现此目的的方法是获取初始文本,并使用空格将其拆分为字符串数组 string.split(' ');
string.split(' ');
接下来,您需要迭代数组中的每个字符串。 这对于单个单词来说很容易,但对于组来说则更复杂。 因此,您需要定义组大小。您必须控制每次迭代时指针前进的数组中的位数。
一旦你能够迭代数组,你需要获取一组单词(无论你选择它多长时间),并将其存储在某个地方。 示例中的词典是一种很好的方法。
如果字典包含单词group,则将其值增加1。 如果它不包含该组,只需添加默认值1即可。
if (wordList.ContainsKey(theKey)) { wordList[theKey]++; } else { wordList.Add(theKey, 1); }
你正确地提到你的研究表明正则表达式并不是高性能。对于这个任务,正则表达式是完全错误的工具 - 你不是在寻找模式,而是在检查组。 为此,您必须从头到尾检查文本,检查值。
任何涉及迭代文本并在其上运行重复函数的任务都不应该使用正则表达式。
编辑:我对正则表达式的初始假设是不正确的 - 在C#中,它似乎比Java更快,但我仍然认为纯正则表达式方法不如使用正则表达式来标记文本那么快然后使用循环或linq表达式来查找组。
说明
@galakt正如我上面提到的,让我们说3.这有关系吗?
单词组的想法完全是抽象的。是的,它是一组单词,但整个文本块是一组单词。 必须应用规则来管理您对该组单词的行为。
下面是一个示例方法,它将根据通过方法调用传递的大小返回所有单词组的字典。 它不会从文本中删除任何非字母数字字符,但即使组大小较大,它也很快。
要打电话,请使用 Dictionary<String, int> SingleWordGroups = GetWordGroupInstances(1);
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; }
下面的方法被修改为依次产生所有组输出,所以 该 绿色的 绿藻 绿藻 等等...
值得注意的是,整个文本必须转换为小写或大写,以便单词不依赖于案例。 我对此进行了一些改进以提高性能(并且不再需要中断指令)。
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个单词组。
这是一种流式方法,它从可枚举的单词中递归地构建大小为N的组(在本例中为3)。将输入标记为单词并不重要(我在本例中使用了一个简单的正则表达式)。
//tokenize input (enumerable of string) var words = Regex.Matches(input, @"\w+").Cast<Match>().Select(m => m.Value); //get word groups (enumerable of string[]) var groups = GetWordGroups(words, 3); //do what you want with your groups; suppose you want to count them var counts = new Dictionary<string, int>(StringComparer.CurrentCultureIgnoreCase); foreach (var group in groups.Select(g => string.Join(" ", g))) { int count; counts.TryGetValue(group, out count); counts[group] = ++count; } IEnumerable<string[]> GetWordGroups(IEnumerable<string> words, int size) { if (size <= 0) throw new ArgumentOutOfRangeException(); if (size == 1) { foreach (var word in words) { yield return new string[] { word }; } yield break; } var prev = new string[0]; foreach (var next in GetWordGroups(words, size - 1)) { yield return next; //stream of groups includes all groups up to size - 1, but we only combine groups of size - 1 if (next.Length == size - 1) { if (prev.Length == size - 1) { var group = new string[size]; Array.Copy(prev, 0, group, 0, prev.Length); group[group.Length - 1] = next[next.Length - 1]; yield return group; } prev = next; } } }
这种流式传输方法的一个优点是可以最大限度地减少内存中必须保留的字符串数量(这会减少大型文本的内存使用)。根据您收到输入的方式,另一种优化可能是使用a TextReader 在读取输入时生成标记枚举。
TextReader
下面是一个中间分组输出的示例(每个项目实际上是令牌数组,在这里用输出的白色空间连接):
The green The green algae green algae The green algae singular algae singular green algae singular green singular green algae singular green alga green alga singular green alga