物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

Windows C#で自然順ソート(Natural Sort Order in C#)

ファイル名に0パディングしない数字があったとき、1 10 2 みたいな順になってしまうのを、1 2 10 に直すためのライブラリ。

stackoverflow.com

Windowsだと、Windowsの標準関数StrCmpLogicalWを使う方法が高速だろう。.NETでも提供してくれたら良いのにな。

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;

namespace ConsoleApp7
{

    class Program
    {
        [SuppressUnmanagedCodeSecurity]
        internal static class SafeNativeMethods
        {
            [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
            public static extern int StrCmpLogicalW(string psz1, string psz2);
        }

        public sealed class NaturalStringComparer : IComparer<string>
        {
            public int Compare(string a, string b)
            {
                return SafeNativeMethods.StrCmpLogicalW(a, b);
            }
        }

        public sealed class NaturalFileInfoNameComparer : IComparer<FileInfo>
        {
            public int Compare(FileInfo a, FileInfo b)
            {
                return SafeNativeMethods.StrCmpLogicalW(a.Name, b.Name);
            }
        }
        static void Main(string[] args)
        {
            // 使い方例1
            List<string> filenames = new List<string> { "test_1.txt", "test_01.txt", "test_001.txt", "test_100.txt", "test_10.txt", "test_2.txt" };
            foreach (var item in filenames) { Console.Write(item + " "); }
            Console.WriteLine("->");
            filenames.Sort(new NaturalStringComparer());
            foreach (var item in filenames) { Console.Write(item + " "); }
            Console.WriteLine();

            // 使い方例2
            List<FileInfo> fileinfos = new List<FileInfo> {
                new FileInfo("test_1.txt"),
                new FileInfo("test_01.txt"),
                new FileInfo("test_001.txt"),
                new FileInfo("test_100.txt"),
                new FileInfo("test_10.txt"),
                new FileInfo("test_2.txt") };
            foreach (var item in fileinfos) { Console.Write(item + " "); }
            Console.WriteLine("->");
            fileinfos.Sort(new NaturalFileInfoNameComparer());
            foreach (var item in fileinfos) { Console.Write(item + " "); }
            Console.WriteLine();
        }
    }
}