C# 解析连续字符串中的单词

C# 解析连续字符串中的单词,c#,algorithm,data-structures,text-segmentation,C#,Algorithm,Data Structures,Text Segmentation,如果a有一个包含单词且没有空格的字符串,那么如果我有一个包含这些单词的字典/列表,我应该如何解析这些单词 例如,如果我的字符串是“ThisisStringWithWords”,我如何使用字典创建输出“ThisisStringWithWords” 我听说使用数据结构可能会有所帮助,但如果有人能帮助处理伪代码呢?例如,我在想,也许你可以把字典索引成一个trie结构,然后按照trie中的每个字符进行排序;问题是,我不熟悉如何在(伪)代码中执行此操作。如果您确定词典中包含该短语的所有单词,您可以使用该算

如果a有一个包含单词且没有空格的字符串,那么如果我有一个包含这些单词的字典/列表,我应该如何解析这些单词

例如,如果我的字符串是“ThisisStringWithWords”,我如何使用字典创建输出“ThisisStringWithWords”


我听说使用数据结构可能会有所帮助,但如果有人能帮助处理伪代码呢?例如,我在想,也许你可以把字典索引成一个trie结构,然后按照trie中的每个字符进行排序;问题是,我不熟悉如何在(伪)代码中执行此操作。

如果您确定词典中包含该短语的所有单词,您可以使用该算法:

String phrase = "thisisastringwithwords";
String fullPhrase = "";
Set<String> myDictionary;
do {
    foreach(item in myDictionary){
        if(phrase.startsWith(item){
            fullPhrase += item + " ";
            phrase.remove(item);
            break;
        }
    }
} while(phrase.length != 0);
String phrase=“thisisstringwithwords”;
字符串fullPhrase=“”;
设置我的字典;
做{
foreach(myDictionary中的项){
如果(短语.开始使用(项目){
完整短语+=项目+“”;
短语.删除(项目);
打破
}
}
}while(短语长度!=0);

有太多的复杂问题,比如,有些项目的开头是一样的,所以代码将被更改为使用某种树搜索,BST等等。

我告诉过你,这似乎是一项不可能完成的任务。但是你可以看一看——这可能会对你有所帮助。

我假设你想要的是一个有效的解决方案,而不是那种反复检查你的文本以字典中的单词开头

如果字典足够小,我想你可以尝试修改标准算法。基本上,在你的字典上建立一个有限状态机,它一个字符一个字符地消耗文本并生成构造的单词


编辑:看来我是在重新发明。

我已经做了类似的事情。你不能使用简单的字典。结果会很混乱。这取决于你是只需要做一次还是整个程序

我的解决办法是:

  • 使用工作模式连接到数据库 词典列表中的单词(用于 示例(在线词典)
  • 过滤字典中的长单词和短单词,并检查是否要精简内容(例如,不要使用只有一个字符的单词,如'I'
  • 从简短的单词开始,将您的大字符串与数据库字典进行比较
  • 现在你需要创建一个“可能性表”。因为很多单词可以100%匹配,但都是错误的。单词越长,你就越确信这个单词是正确的。

    它是cpu密集型的,但它可以在结果中精确地工作。 比如说,你正在使用一个10000字的小词典,其中3000字的长度为8个字符,你需要在开始时将你的大字符串与所有3000字进行比较,只有找到结果,才允许继续下一个字。如果你的大字符串中有200个字符,你需要大约(2000个字符/8个平均字符)=250个完整回路,最小带比较

    对我来说,我还对拼错的单词做了一个小的验证

    过程示例(不复制粘贴)

    Dim bigString As String=“helloworld.thisistackoverflowtest!”
    Dim dictionary As New List(字符串)“”包含原始单词。让其不区分大小写
    dictionary.Add(“你好”)
    添加(“世界”)
    字典。添加(“本”)
    添加(“is”)
    字典。添加(“a”)
    dictionary.Add(“堆栈”)
    字典。添加(“结束”)
    dictionary.Add(“流”)
    dictionary.Add(“stackoverflow”)
    添加(“测试”)
    字典。添加(“!”)
    将每个单词作为字典中的字符串
    如果word.Length<1,则dictionary.Remove(word)'删除短单词(不适用于实际中的每个单词)
    word=word.ToLower'使其大小写不敏感
    下一个
    Dim ResultComparer As New Dictionary(字符串的,双精度)“”字符串是字典中的单词。双精度是自身函数对结果加权的百分比值
    Dim i作为整数=0'从开头开始
    发现Dim为布尔值=False
    做
    对于字典中的每个单词
    如果bigString.IndexOf(word,i)>0,那么
    结果comparer.Add(word,MyWeightOfWord)'添加单词如果发现,长单词会更好,并且会增加权重值
    找到=真
    如果结束
    下一个
    如果find=True,则
    i+=结果比较器(最佳单词和最佳权重)。长度
    其他的
    i+=1
    如果结束
    环
    
    这正是试图以编程方式解析单词之间没有空格的语言(如中文)时遇到的问题。这些语言的一种有效方法是从标点符号上拆分文本开始。这将为您提供短语。接下来,您迭代短语,并尝试将其拆分为以le开头的单词词典中最长单词的长度。假设长度为13个字符。从短语中提取前13个字符,看看它是否在词典中。如果是,现在将其作为正确的单词,在短语中向前移动并重复。否则,将子字符串缩短为12个字符,然后再缩短为11个字符,以此类推

    这非常有效,但并不完美,因为我们无意中对最先出现的单词产生了偏见。消除这种偏见并仔细检查结果的一种方法是从短语末尾开始重复这个过程。如果你得到相同的分词,你可能会说它是好的。如果不是,你有一个重叠的词段。例如,当您解析从末尾开始的示例短语时,您可能会得到(向后强调)

    首先,单词Isis(埃及女神)似乎是正确的单词。但是,当您发现词典中没有“th”时,您知道附近有一个分词问题。请使用未对齐序列“this”的正向分词结果“this is”来解决此问题,因为这两个词都在词典中

    这个问题的一个不太常见的变体是当
        Dim bigString As String = "helloworld.thisisastackoverflowtest!"
    
        Dim dictionary As New List(Of String) 'contains the original words. lets make it case insentitive
        dictionary.Add("Hello")
        dictionary.Add("World")
        dictionary.Add("this")
        dictionary.Add("is")
        dictionary.Add("a")
        dictionary.Add("stack")
        dictionary.Add("over")
        dictionary.Add("flow")
        dictionary.Add("stackoverflow")
        dictionary.Add("test")
        dictionary.Add("!")
    
    
        For Each word As String In dictionary
            If word.Length < 1 Then dictionary.Remove(word) 'remove short words (will not work with for each in real)
            word = word.ToLower 'make it case insentitive
        Next
    
        Dim ResultComparer As New Dictionary(Of String, Double) 'String is the dictionary word. Double is a value as percent for a own function to weight result
    
        Dim i As Integer = 0 'start at the beginning
        Dim Found As Boolean = False
        Do
            For Each word In dictionary
                If bigString.IndexOf(word, i) > 0 Then
                    ResultComparer.Add(word, MyWeightOfWord) 'add the word if found, long words are better and will increase the weight value 
                    Found = True
                End If
            Next
            If Found = True Then
                i += ResultComparer(BestWordWithBestWeight).Length
            Else
                i += 1
            End If
        Loop
    
    words with string a Isis th
    
    Class State 
    {
       String matchedWord;
       Map<char,State> mapChildren;
    }
    
    public static String[] StringToWords(String str, HashSet<string> words)
    {      
      //Index of char - length of last valid word
      int[] bps = new int[str.Length + 1];
    
      for (int i = 0; i < bps.Length; i++)      
        bps[i] = -1;
    
      for (int i = 0; i < str.Length; i++)
      {
        for (int j = i + 1; j <= str.Length ; j++)
        {
          if (bps[j] == -1)
          {
            //Destination cell doesn't have valid backpointer yet
            //Try with the current substring
            String s = str.Substring(i, j - i);
            if (words.Contains(s))
              bps[j] = i;
          }
        }        
      }      
    
      //Backtrack to recovery sequence and then reverse 
      List<String> seg = new List<string>();
      for (int bp = str.Length; bps[bp] != -1 ;bp = bps[bp])      
        seg.Add(str.Substring(bps[bp], bp - bps[bp]));      
      seg.Reverse();
      return seg.ToArray();
    }
    
    foreach (var s in StringSplitter.StringToWords("thisisastringwithwords", dict))
        Console.WriteLine(s);