最終更新日 2024-09-25

NET5には、文字列比較に大きな落とし穴がある

概要

秀丸に限定する話ではなく、.NET4や.NET Core3.1 までと、.NET5では
「文字列」の扱いが「NLS」というものから「ICU」という規格に変更しているという点です。

このことが文字列比較において、「え、そんなはずはない」といった結果を返すことがあります。

文字列の中のindexOf

ICUとCRLFの落とし穴
...
    string s = "Hello\r\nworld!";
    int idx = s.IndexOf("\n");
    Console.WriteLine(idx); // idx は「-1」となる。即ち文字列中に「\n」は無いと判定されてしまう。

ICUの判定では、「\r\n」(CRLF)は文字列としては「2つの長さ」であるにもかかわらず「不可分」であり、
「\n」といった単体文字は「存在しない」と判断されてしまいます。
ここがおそらくは一番プログラム的な落とし穴となることでしょう。

解消方法

プロジェクトファイルを以下のように書き換えるのが良いかもしれません。
文字列比較まわりでエラーを出すようにするとともに、新しいICUではなく古いNLSを使うように変更するものです。

****.csproj
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>Library</OutputType>
        <TargetFramework>net5.0</TargetFramework>
        <WarningsAsErrors>$(WarningsAsErrors);CA1307;CA1309;CA1310</WarningsAsErrors>
    </PropertyGroup>
    
    <ItemGroup>
        <RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
    </ItemGroup>
</Project>
        
ICUとCRLFの落とし穴
...
    string s = "Hello\r\nworld!";
    int idx = s.IndexOf("\n", StringComparison.CurrentCulture);
    Console.WriteLine(idx); // idx は「6」となる。即ち文字列中に「\n」があると判定される。従来通り。

これにより、「ICU」ではなく「NLS」が利用されますので、.NET4.x までと同じ文字列比較のアルゴリズムとなります。

しかし、将来の方向性は、あくまで全てのメジャーなOSで文字列の扱いや比較アルゴリズムは「ICU」になってゆきますので、
移行初期はやむを得ないとしても、ICUで上手くいくようなアルゴリズムへと、徐々に移行してゆくべきでしょう。