今天做项目时候遇到一个小问题,我这边需要读取一个文件路径,路径下的信息如下:
C#中,我们可以使用Directory.GetFiles(${path})方法获取路径下指定的文件列表,然而当我们获取如上路径后,得到的结果如下:
可以看到,1之后直接是10.*,11.*,12.*,这很明显和我们期望的出入有些大,这时候需要使用自然排序,在.NET中可以使用 AlphanumComparatorFast进行排序,nuget:
Install-Package AlphanumComparatorFast -Version 1.0.6
代码如下:
string[] fileNames = Directory.GetFiles(@"C:\path\to\your\folder");
var sortedFileNames = fileNames.OrderBy(f => f, new AlphanumComparatorFast());
foreach (string fileName in sortedFileNames)
{
Console.WriteLine(fileName);
}
也可以使用Humanizer.Core进行自然排序
string[] fileNames = Directory.GetFiles(@"C:\path\to\your\folder");
var sortedFileNames = fileNames.OrderBy(f => f, StringComparer.OrdinalIgnoreCase.WithNaturalSort());
foreach (string fileName in sortedFileNames)
{
Console.WriteLine(fileName);
}
重点来了
如果以上方法都无效:那只能自己写了(内心是崩溃的)
接下来使用.NET实现一个自然排序算法:
public class NaturalStringComparer : IComparer
{
private const string pattern = @"(\d+)";
public int Compare(string x, string y)
{
if (x == null || y == null)
{
return 0;
}
string[] xParts = Regex.Split(x.Replace(" ", ""), pattern);
string[] yParts = Regex.Split(y.Replace(" ", ""), pattern);
int i = 0;
while (true)
{
if (i == xParts.Length && i == yParts.Length)
{
return 0;
}
else if (i == xParts.Length)
{
return -1;
}
else if (i == yParts.Length)
{
return 1;
}
if (xParts[i] != yParts[i])
{
if (int.TryParse(xParts[i], out int xNum) && int.TryParse(yParts[i], out int yNum))
{
return xNum.CompareTo(yNum);
}
else
{
return string.Compare(xParts[i], yParts[i], StringComparison.OrdinalIgnoreCase);
}
}
i++;
}
}
}
使用方法:
string[] fileNames = { "file10.txt", "file2.txt", "file1.txt", "file11.txt" };
Array.Sort(fileNames, new NaturalStringComparer());
foreach (string fileName in fileNames)
{
Console.WriteLine(fileName);
}
搞定。