нечеткое сравнение строк (проверка на соответствие) C # - PullRequest
0 голосов
/ 03 июня 2018

У меня есть два списка строк, и я хочу извлечь из каждого списка индекс, если строка с текущим индексом находится во втором списке (и наоборот), строка не может точно соответствовать или может быть сокращением другого списканапример, рассмотрим этот два списка

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

индексы 1,2 из aList, очевидно, что строка соответствует полностью, но интересной частью являются "EquipType" и "EquipmentType" , которые match , потому что "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();

приведенный выше код работает очень хорошо и выглядит очень похожек этому решению

, но если изменить порядок второго списка следующим образом:

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

я получуИндекс 0, 1 и 3 (но я хочу 0 2 и 3)

Должен ли я проверить расстояние для каждой пары и вернуть наименьшее?или я должен работать другим методом

Спасибо

PS Я также нашел этот GitHub, но я не знаю, будет ли это для меня хитростью

1 Ответ

0 голосов
/ 03 июня 2018

Я чувствую, что то, что вы пытаетесь сделать, - плохая идея ... Id - это сокращение от Idiotic , просто для примера :-) Тем не менее ...Я хотел сделать несколько экспериментов на Unicode.

Теперь этот код будет разбивать слова на заглавные буквы.PartName - это Part + Name, потому что N - это прописные буквы.Он не поддерживает ID как Identifier (потому что это должно быть IDentifier), но он поддерживает NSA как NotSuchAgency :-) Так что полные аббревиатуры в порядке, тогда как FDA не эквивалентноFoodAndDrugAdministration, поэтому аббревиатуры с конъюнкциями - это КО.

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<List<int>>, поскольку вы можете иметь несколько совпадений для одного слова aList!

Теперь ... интересная часть ShorthandCompare состоит в том, что он пытается быть "интеллектуальным" и обрабатывать символы не-BMP Unicode (с помощью StringInfo.GetTextElementEnumerator) и обрабатывать разложенные символы Unicode (символ ì можетбыть полученным в Юникоде через i + \u0300, то есть его диерезис).Он делает это с помощью string.Compare, который, в отличие от string.Equals, поддерживает Unicode (string.CompareOrdinal больше похож на string.Equals и не поддерживает Unicode).

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