天天看點

記一次系統遷移遇到的中文字元串排序問題

作者:opendotnet

背景

不久前,遷移了一個 framework 項目到 .net core 上面,部署也從 Windows 的 IIS 到 linux 的容器化。

期間遇到了一個關于中文字元串排序的問題,在這裡記錄一下。

複現與處理

下面這段代碼就是出現問題的代碼。

var list = new List<string>
{ 
"阿莫西林", "阿司匹林", "阿卡波糖"
};

list.Sort();

foreach (var item in list)
{
 Console.WriteLine(item);
}
           

大家覺得,排序後的結果會是怎麼樣的呢?

這個排序結果其實取決于目前環境的 CultureInfo,因為

list.Sort()

最後會調用

Array.Sort<T>(Array keys, Array? items, int index, int length, IComparer? comparer)

,沒有顯式的傳遞

comparer

參數,這個時候就會用到

Comparer.Default

,這個 default 的構造函數就傳入了 CultureInfo.CurrentCulture。

大體調用邏輯可以參考下面的 4 個 github 連結

https://github.com/dotnet/runtime/blob/dfe1076090adad6990747e6abed8bf6699371877/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/List.cs#L1046 https://github.com/dotnet/runtime/blob/dfe1076090adad6990747e6abed8bf6699371877/src/libraries/System.Private.CoreLib/src/System/Array.cs#L1817 https://github.com/dotnet/runtime/blob/dfe1076090adad6990747e6abed8bf6699371877/src/libraries/System.Private.CoreLib/src/System/Array.cs#L1850 https://github.com/dotnet/runtime/blob/dfe1076090adad6990747e6abed8bf6699371877/src/libraries/System.Private.CoreLib/src/System/Collections/Comparer.cs#L21

知道這個的話,就可以來驗證一下了。

記一次系統遷移遇到的中文字元串排序問題

本地調試輸出如下:

記一次系統遷移遇到的中文字元串排序問題

基于

mcr.microsoft.com/dotnet/runtime:6.0-bullseye-slim

鏡像,

docker build -t sort:v1 -f .\Dockerfile .
docker run --rm sort:v1
           

放到容器下面輸出如下:

記一次系統遷移遇到的中文字元串排序問題

可以看到,預設的是為空的,也就是沒有任何指定。

由于 bullseye-slim 鏡像已經包含了 icu 相關的庫,是以可以直接指定 LC_ALL 或 LANG 為 zh_CN 即可。

docker run --rm -e LC_ALL=zh_CN sort:v1
# 或
docker run --rm -e LANG=zh_CN sort:v1
           

這個時候的輸出就是和本地調試一緻的了。

是以最後的解決方案是 添加多一個環境變量 來解決這個問題。遷移雖然簡單,一些小細節還是要注意的!!

如果是用 alpine 鏡像的話,要注意安裝 icu 相關的庫。

參考資料

  • https://learn.microsoft.com/zh-cn/previous-versions/bb688122(v=msdn.10)?redirectedfrom=MSDN
  • https://learn.microsoft.com/zh-cn/dotnet/api/system.globalization.cultureinfo?view=net-7.0
  • https://github.com/dotnet/runtime/issues/59193

繼續閱讀