在字符串中找到最准确的匹配
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()));
我正在开发一种工具,通过在 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()));