【问题标题】:fuzzy string compare (check for shorthand matching) C#模糊字符串比较(检查速记匹配)C#
【发布时间】:2018-06-03 07:34:32
【问题描述】:

我有两个字符串列表,如果当前索引处的字符串在第二个列表中(反之亦然),我想从每个列表中提取索引,字符串不能完全匹配或者可以是另一个列表的简写,例如,考虑这两个列表

List<string> aList = new List<string> { "Id", "PartCode", "PartName", "EquipType" };
List<string> bList = new List<string> { "PartCode", "PartName", "PartShortName", "EquipmentType" };

在上面的例子中,我想从aList索引:1,2,3

bList 索引 0,1,3

aList 中的索引 1,2 显然是完全匹配的字符串,但有趣的部分是 "EquipType""EquipmentType" 其中 匹配 因为 “EquipType”“EquipmentType”的简写

"PartName" 不是 "PartShortName"简写,因此不需要索引

这是我的代码

List<string> aList = new List<string> { "Id", "PartCode", "PartName", "EquipType" };// 1, 2 , 3
List<string> bList = new List<string> { "PartCode", "PartName", "PartShortName", "EquipmentType" };//0, 1 ,3 

List<int> alistIndex = new List<int>();
List<int> blistIndex = new List<int>();

for (int i = 0; i < aList.Count; i++)           
{
    string a = aList[i];
    for (int j = 0; j < bList.Count(); j++)               
    {
        string b = bList[j];

        string bigger, smaller;
        int biggerCount, smallerCount;
        if (a.Length > b.Length)
        {
            bigger = a; smaller = b;
            biggerCount = a.Length ; smallerCount = b.Length ;    
        }
        else
        {
            bigger = b; smaller = a;
            biggerCount = b.Length; smallerCount = a.Length ;
        }

        int countCheck = 0;
        for (int k = 0; k < biggerCount; k++)
        {
            if (smaller.Length != countCheck)
            {
                if (bigger[k] == smaller[countCheck])
                    countCheck++;
             }
         }

        if (countCheck == smaller.Length)
        {
            alistIndex.Add(i);
            blistIndex.Add(j);
            res = true;
            break;
        }
        else
            res = false;  
    }
}

alistIndex.ForEach(i => Console.Write(i));
Console.WriteLine(Environment.NewLine);
blistIndex.ForEach(i => Console.Write(i));
Console.ReadKey();

上面的代码工作得很好,看起来和solution很相似

但是如果像这样改变第二个列表的顺序

 List<string> bList = new List<string> { "PartCode", "PartShortName", "PartName", "EquipmentType" };

我将得到索引 0、1 和 3(但我想要 0、2 和 3)

我应该检查每对的距离并返回最低的吗?还是我应该用不同的方法工作

谢谢

附言 我还找到了this GitHub,但我不知道它是否对我有用

【问题讨论】:

  • 你认为“EquipType”和“EquipmentType”是一样的吗?
  • @L_J 你是什么意思?
  • 请仔细检查您的示例和索引,我可以发誓您自相矛盾。还要清楚你的意思,你不能让它在一种情况下工作,而不是另一种情况下的速记......根据@L_J问题。他试图弄清楚你想要什么,因为它似乎并不明确。
  • @Seabizkit 也许速记不是描述我想要的东西的正确词,但也许“缩写”会更合适(如美国和美国,EquipType 和 EquipmentType 也是如此,但 PartName PartShortName 不是)我是吗?现在更清楚了吗?
  • 问题实际上是关于如何比较两个字符串。之后,列表的比较是微不足道的。那么,当您认为两个字符串“相同”时,确切的标准是什么?

标签: c# string fuzzy-comparison


【解决方案1】:

我确实觉得你正在尝试做的是一个坏主意... IdIdiotic 的缩写,只是举个例子:-) 仍然...我想对 Unicode 做一些实验。

现在,此代码将按大写字母拆分单词。 PartNamePart + Name,因为 N 是大写的。它不支持ID 作为Identifier(因为它应该是IDentifier)但它支持NSA 作为NotSuchAgency :-) 所以完整的首字母缩写词是可以的,而FDA 不等于FoodAndDrugAdministration,所以带有连词的首字母缩写词是 KO。

public static bool ShorthandCompare(string str1, string str2)
{
    if (str1 == null)
    {
        throw new ArgumentNullException(nameof(str1));
    }

    if (str2 == null)
    {
        throw new ArgumentNullException(nameof(str2));
    }

    if (str1 == string.Empty)
    {
        return str2 == string.Empty;
    }

    if (object.ReferenceEquals(str1, str2))
    {
        return true;
    }

    var ee1 = StringInfo.GetTextElementEnumerator(str1);
    var ee2 = StringInfo.GetTextElementEnumerator(str2);

    bool eos1, eos2 = true;

    while ((eos1 = ee1.MoveNext()) && (eos2 = ee2.MoveNext()))
    {
        string ch1 = ee1.GetTextElement(), ch2 = ee2.GetTextElement();

        // The string.Compare does some nifty tricks with unicode
        // like string.Compare("ì", "i\u0300") == 0
        if (string.Compare(ch1, ch2) == 0)
        {
            continue;
        }

        UnicodeCategory uc1 = char.GetUnicodeCategory(ch1, 0);
        UnicodeCategory uc2 = char.GetUnicodeCategory(ch2, 0);

        if (uc1 == UnicodeCategory.UppercaseLetter)
        {
            while (uc2 != UnicodeCategory.UppercaseLetter && (eos2 = ee2.MoveNext()))
            {
                ch2 = ee2.GetTextElement();
                uc2 = char.GetUnicodeCategory(ch2, 0);
            }

            if (!eos2 || string.Compare(ch1, ch2) != 0)
            {
                return false;
            }

            continue;
        }
        else if (uc2 == UnicodeCategory.UppercaseLetter)
        {
            while (uc1 != UnicodeCategory.UppercaseLetter && (eos1 = ee1.MoveNext()))
            {
                ch1 = ee1.GetTextElement();
                uc1 = char.GetUnicodeCategory(ch1, 0);
            }

            if (!eos1 || string.Compare(ch1, ch2) != 0)
            {
                return false;
            }

            continue;
        }

        // We already know they are different!
        return false;
    }

    if (eos1)
    {
        while (ee1.MoveNext())
        {
            string ch1 = ee1.GetTextElement();
            UnicodeCategory uc1 = char.GetUnicodeCategory(ch1, 0);

            if (uc1 == UnicodeCategory.UppercaseLetter)
            {
                return false;
            }
        }
    }
    else if (eos2)
    {
        while (ee2.MoveNext())
        {
            string ch2 = ee2.GetTextElement();
            UnicodeCategory uc2 = char.GetUnicodeCategory(ch2, 0);

            if (uc2 == UnicodeCategory.UppercaseLetter)
            {
                return false;
            }
        }
    }

    return true;
}

然后

List<string> aList = new List<string> { "Id", "PartCode", "PartName", "EquipType" };
List<string> bList = new List<string> { "PartCode", "PartName", "PartShortName", "EquipmentType" };

List<List<int>> matches = new List<List<int>>();

for (int i = 0; i < aList.Count; i++)
{
    var lst = new List<int>();
    matches.Add(lst);

    for (int j = 0; j < bList.Count; j++)
    {
        if (ShorthandCompare(aList[i], bList[j]))
        {
            lst.Add(j);
        }
    }
}

请注意,结果是List&lt;List&lt;int&gt;&gt;,因为aList 的单个单词可能有多个匹配项!

现在...ShorthandCompare 的有趣之处在于它试图变得“智能”并处理非 BMP Unicode 字符(通过使用 StringInfo.GetTextElementEnumerator)并处理分解的 Unicode 字符(ì字符可以通过i+\u0300在Unicode中获得,即它的分词)。它通过使用string.Compare 来做到这一点,与string.Equals 不同的是,它可以识别Unicode(string.CompareOrdinal 更类似于string.Equals,而不是识别Unicode)。

bool cmp1 = ShorthandCompare("IdìoLe\u0300ss", "Idi\u0300oticLèsser"); // true

【讨论】:

    猜你喜欢
    • 2012-04-27
    • 2014-12-30
    • 1970-01-01
    • 2012-02-14
    • 2014-11-02
    • 2018-05-31
    • 2021-04-19
    • 1970-01-01
    • 2015-06-22
    相关资源
    最近更新 更多