在字符串中找到最准确的匹配

Find most accurate match in strings

我正在开发一种工具,通过在 YouTube 播放列表中搜索正确的名称来修复不正确的文件名。此工具获取 YouTube 播放列表视频的标题并将它们存储在列表中:

static List<string> tracksList = new List<string>();

在此列表中存储所有正确名称后,该工具将在文件夹中执行搜索,它只会搜索扩展名为“.mp3”的文件:

DirectoryInfo dir = new DirectoryInfo(@"C:\folder");
FileInfo[] files = musicDir.GetFiles("*.mp3", SearchOption.TopDirectoryOnly);

将所有 MP3 文件存储在 FileInfo 数组中后,循环遍历所有文件。此循环将逐个文件,并根据每个文件的文件名,检查哪个是 trackList 列表中最相似的值。我已经尝试过这个,但它 return 一个空数组:

var trackMatch = tracksList.Where(track => track.Contains(file.Name.Replace(".mp3", "")))
                           .ToArray();

有什么办法可以做到吗?

这是一项 non-trivial 任务。

问题当然是文件名中的错误可以是任何东西,从拼写错误到遗漏单词再到添加空格..

这意味着任何字符可以任何方式受到影响。

因此,无论是简单的 Contains 还是聪明的 RegEx 都无法可靠地工作。

我会将文件名拆分为 words 并计算 count 我在列表标题中找到的单词数量。计数最高的人最有可能成为正确的人。

我也会尝试参加 semi-automatic 计划,在那里我会得到按点击次数排序的选择,然后可以确认、更正或通过..

可以使用 Levenshtein 算法执行字符串比较 (more information). The implementations for this algorithm can be found here.

函数(计算必须更改多少个字符才能拥有另一个字符串)如下(摘自https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C.23):

public static int LevenshteinDistance(string source, string target)
{
    if (String.IsNullOrEmpty(source))
    {
        if (String.IsNullOrEmpty(target)) return 0;
            return target.Length;
    }
    if (String.IsNullOrEmpty(target)) return source.Length;

    if (source.Length > target.Length)
    {
        var temp = target;
        target = source;
        source = temp;
    }

    var m = target.Length;
    var n = source.Length;
    var distance = new int[2, m + 1];
    // Initialize the distance 'matrix'
    for (var j = 1; j <= m; j++) distance[0, j] = j;

    var currentRow = 0;
    for (var i = 1; i <= n; ++i)
    {
        currentRow = i & 1;
        distance[currentRow, 0] = i;
        var previousRow = currentRow ^ 1;
        for (var j = 1; j <= m; j++)
        {
            var cost = (target[j - 1] == source[i - 1] ? 0 : 1);
            distance[currentRow, j] = Math.Min(Math.Min(
                distance[previousRow, j] + 1,
                distance[currentRow, j - 1] + 1),
                distance[previousRow, j - 1] + cost);
        }
    }
    return distance[currentRow, m];
}

因此,如果使用前面的函数将输入字符串与trackList中存储的每个字符串进行比较,我们将得到Levenshtein值:最小的表示最相似:

static List<int> matchList = new List<int>();
foreach (string Track in tracksList)
{
    matchList.Add(LevenshteinDistance(Track, "Dailucia   Where My Heart Matches The Beat (Ft Poprebel) [FULL HQ + HD]"));
}
string match = tracksList.ElementAt(matchList.IndexOf(matchList.Min()));