【问题标题】:Find most accurate match in strings在字符串中查找最准确的匹配
【发布时间】:2015-02-21 14:40:46
【问题描述】:

我正在开发一种工具,该工具通过在 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 列表中最相似的值。我已经尝试过了,但它确实返回了一个空数组:

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

有什么办法可以做到吗?

【问题讨论】:

  • 您使用的代码行只是生成一个列表,不会更改文件名,您遇到的具体问题是什么?
  • by "any stored value" 如果你的意思是标题中的一个词,你会遇到常用词和文章的问题。然后会出现标题没有元数据([FULL HQ + HD])但其他匹配的问题

标签: c# comparison compare match


【解决方案1】:

可以使用 Levenshtein 算法 (more information) 执行字符串比较。这个算法的实现可以在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];
}

因此,如果使用前面的函数将输入字符串与存储在tracksList中的每个字符串进行比较,我们将得到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()));

【讨论】:

    【解决方案2】:

    这是一项不平凡的任务。

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

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

    因此,无论是简单的 Contains 还是智能的 RegEx 都不会可靠地工作。

    我会将文件名拆分为 单词,然后对我在列表标题中找到的单词数量进行 count。计数最高的人最有可能成为正确的人。

    我也会尝试使用半自动程序,在该程序中,我会获得按命中数排序的选项,然后可以确认、更正或通过..

    【讨论】:

      猜你喜欢
      • 2016-07-01
      • 1970-01-01
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多