【问题标题】:English Dictionary word matching from a string来自字符串的英语词典单词匹配
【发布时间】:2012-07-28 08:06:10
【问题描述】:

我正试图解决一个问题,即从字典文件中识别英语单词与给定字符串的最佳匹配。

例如(“lines”是字典单词的列表):

string testStr = "cakeday";

for (int x= 0; x<= testStr.Length; x++)
{
  string test = testStr.Substring(x);

   if (test.Length > 0)
   {
      string test2 = testStr.Remove(counter);
      int count = (from w in lines where w.Equals(test) || w.Equals(test2) select w).Count();
      Console.WriteLine("Test: {0} / {1} : {2}", test, test2, count);
    }
}

给出输出:

Test: cakeday /   : 0
Test: akeday / c  : 1
Test: keday / ca  : 0
Test: eday / cak  : 0
Test: day / cake  : 2
Test: ay / caked  : 1
Test: y / cakeda  : 1

显然“day / cake”最适合字符串,但是如果我要在字符串中引入第三个单词,例如“cakedaynow”,它就不会那么好用了。

我知道这个例子很原始,它更像是一个概念证明,想知道是否有人对这种类型的字符串分析有任何经验?

谢谢!

【问题讨论】:

  • “cakeday”不是,也永远不会是英语词典的一部分。拿那个,reddit!
  • 我猜counterx是一样的
  • 显然@KonradRudolph 认为蛋糕是谎言。
  • 是的,抱歉,计数器应该是 x

标签: c# .net linq


【解决方案1】:

为什么不呢:

检查搜索词中的所有字符串,从当前搜索位置提取到字符串的所有可能长度,并提取所有发现的词。例如:

var list = new List<string>{"the", "me", "cat", "at", "theme"};
const string testStr = "themecat";
var words = new List<string>();
var len = testStr.Length;
for (int x = 0; x < len; x++)
{
    for(int i = (len - 1); i > x; i--)
    {
        string test = testStr.Substring(x, i - x + 1);
        if (list.Contains(test) && !words.Contains(test))
        {
            words.Add(test);
        }
    }
}

words.ForEach(n=> Console.WriteLine("{0}, ",n));//spit out current values

输出:

主题,我,猫,在

编辑

现场场景 1: 例如,假设您希望始终选择混乱句子中最长的单词,您可以从前向前阅读,从而减少阅读的文本量,直到读完为止。使用字典更容易,通过存储发现单词的索引,我们可以快速检查我们是否存储了一个包含另一个我们正在评估的单词的单词。

示例:

var list = new List<string>{"the", "me", "cat", "at", "theme", "crying", "them"};
const string testStr = "themecatcryingthem";
var words = new Dictionary<int, string>();
var len = testStr.Length;
for (int x = 0; x < len; x++)
{
    int n = len > 28 ? 28 : len;//assuming 28 is the maximum length of an english word
    for(int i = (n - 1); i > x; i--)
    {
        string test = testStr.Substring(x, i - x + 1);
        if (list.Contains(test))
        {
            if (!words.ContainsValue(test))
            {
                bool found = false;//to check if there's a shorter item starting from same index
                var key = testStr.IndexOf(test, x, len - x);
                foreach (var w in words)
                {
                    if (w.Value.Contains(test) && w.Key != key && key == (w.Key + w.Value.Length - test.Length))
                    {
                        found = true;
                    }
                }
                if (!found && !words.ContainsKey(key)) words.Add(key, test);
            }
        }
    }
}

words.Values.ToList().ForEach(n=> Console.WriteLine("{0}, ",n));//spit out current values

输出:

主题,猫,哭,他们

【讨论】:

  • 我试过你的代码,但不幸的是它没有给我我希望的结果。我应该补充一点,整个字符串必须用尽可能少的单词匹配,所以对于 ex,“themecat”应该输出到“theme cat”而不是“the me cat”,因为它可以说是最短路径。
  • 实际上我想我已经找到了另一个 SO 问题的解决方案,现在将其转换为 C# :) stackoverflow.com/a/195024/243935
  • @chrr:我的代码中的第二种方法解决了这个问题。我做过很多关于人工智能和字符串操作的项目,所以这类事情对我来说一点也不新鲜或复杂。
  • 用外行的话来说,您可以使用上述方法从“themecat”中正确获取“主题猫”,方法是遍历列表中的每个单词并删除它们包含的任何其他字符串,这些字符串是列表中的单词.如果你愿意,我可以用这个为你更新代码。
  • 完成了,但是写的有点匆忙。如果您将它用于大量数据,我想看看性能结果。您可以查看wordnet 获取一些字典集合。
【解决方案2】:

你会想要研究适合你想要做的事情的算法类别。从维基百科上的Approximate string matching 开始。

另外,这里有一个用 C# 编写的 Levenshtein Edit Distance 实现来帮助您入门:

using System;

namespace StringMatching
{
    /// <summary>
    /// A class to extend the string type with a method to get Levenshtein Edit Distance.
    /// </summary>
    public static class LevenshteinDistanceStringExtension
    {
        /// <summary>
        /// Get the Levenshtein Edit Distance.
        /// </summary>
        /// <param name="strA">The current string.</param>
        /// <param name="strB">The string to determine the distance from.</param>
        /// <returns>The Levenshtein Edit Distance.</returns>
        public static int GetLevenshteinDistance(this string strA, string strB)
        {
            if (string.IsNullOrEmpty(strA) && string.IsNullOrEmpty(strB))
                return 0;

            if (string.IsNullOrEmpty(strA))
                return strB.Length;

            if (string.IsNullOrEmpty(strB))
                return strA.Length;

            int[,] deltas; // matrix
            int lengthA;
            int lengthB;
            int indexA;
            int indexB;
            char charA;
            char charB;
            int cost; // cost

            // Step 1
            lengthA = strA.Length;
            lengthB = strB.Length;

            deltas = new int[lengthA + 1, lengthB + 1];

            // Step 2
            for (indexA = 0; indexA <= lengthA; indexA++)
            {
                deltas[indexA, 0] = indexA;
            }

            for (indexB = 0; indexB <= lengthB; indexB++)
            {
                deltas[0, indexB] = indexB;
            }

            // Step 3
            for (indexA = 1; indexA <= lengthA; indexA++)
            {
                charA = strA[indexA - 1];

                // Step 4
                for (indexB = 1; indexB <= lengthB; indexB++)
                {
                    charB = strB[indexB - 1];

                    // Step 5
                    if (charA == charB)
                    {
                        cost = 0;
                    }
                    else
                    {
                        cost = 1;
                    }

                    // Step 6
                    deltas[indexA, indexB] = Math.Min(deltas[indexA - 1, indexB] + 1, Math.Min(deltas[indexA, indexB - 1] + 1, deltas[indexA - 1, indexB - 1] + cost));
                }
            }

            // Step 7
            return deltas[lengthA, lengthB];
        }
    }
}

【讨论】:

    猜你喜欢
    • 2012-03-23
    • 2019-02-23
    • 2016-07-18
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    相关资源
    最近更新 更多