0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Windows 日本語カルチャ照合規則 - 漢字ソート順

Last updated at Posted at 2025-02-13

はじめに

C#定石 - ファイル一覧 - 照合規則 で、任意にピックアップした漢字を、Windows 日本語カルチャ照合規則でソートした結果を確認しました。

文字 Unicode JIS X0213 水準 画数 部首 音読み
U+4E00 1-16-76 第1水準 1 一部 イチ・イツ
U+4E09 1-27-16 第1水準 3 一部 サン
U+4E8C 1-38-83 第1水準 2 二部
U+4E9C 1-16-1 第1水準 7 二部
U+4E9E 1-48-19 第2水準 8 二部
U+5516 1-16-2 第1水準 10 口部 ア・アク
U+555E 1-15-8 第3水準 11 口部 ア・アク
U+5561 2-4-8 第4水準 11 口部 ハイ・ヒ
U+6392 1-39-51 第1水準 11 手部 ハイ
U+67DB 2-14-50 第4水準 9 木部 シン
U+795E 1-31-32 第1水準 9 示部 シン・ジン
U+FA19 1-89-28 第3水準 10 示部 シン・ジン
var arrayItems4 = new string[] { "一", "三", "二", "亜", "亞", "唖", 
                                 "啞", "啡", "排", "柛", "神", "神" };
Array.Sort(arrayItems4);
// → "亜", "唖", "一", "三", "神", "二", "排", "亞", "神", "啞", "啡", "柛"

JIS X 0213 面区点順をベースとしているようですが、「啞」がイレギュラーという結果になったので、漢字ソート順を確認してみることにします。

参考情報

下記情報を参考にさせて頂きました。

テスト環境

ここに記載した情報/ソースコードは、Visual Studio Community 2022 を利用した下記プロジェクトで生成したモジュールを Windows 11 24H2 で動作確認しています。

  • Windows Forms - .NET Framework 4.8
  • Windows Forms - .NET 8
  • WPF - .NET Framework 4.8
  • WPF - .NET 8

Visual Studio 2022 - .NET Framework 4.8 は、C# 7.3 が既定です。
このため、サンプルコードは、C# 7.3 機能範囲で記述しています。

漢字ソート順

テストデータ作成とソート実行

まず、 JIS X 0213漢字一覧 - Wikipedia から、「JIS X 0213漢字一覧の1面」「JIS X 0213漢字一覧の2面」を、Unicode タブ区切りテキストファイルに落とします。

対象ファイルの項目は「文字」「面区点」「Shift_JIS-2004」「Unicode」「水準」「備考」となっていますが、「文字」「面区点」「水準」「Unicode」「UTF16」に変更します。

// 原本 TSV → 今回利用 TSV
private void Original2Custom(string original, string custom)
{
  using (var sr = new StreamReader(original, Encoding.UTF8))
  using (var sw = new StreamWriter(custom, false, Encoding.UTF8))
  {
    // ヘッダー
    // original「文字」「面区点」「Shift_JIS-2004」「Unicode」「水準」「備考」
    // → custom「文字」「面区点」「水準」「Unicode」「UTF16」
    var line = sr.ReadLine();
    sw.WriteLine("文字\t面区点\t水準\tUnicode\tUTF16");

    // データ
    while (sr.Peek() > -1)
    {
      // 1行取得してタブ区切りで分解
      line = sr.ReadLine().Trim();
      var items = line.Split('\t');
      if (items?.Length >= 5)
      {
        sw.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}\t{4}",
                              parts[0].Trim(), parts[1].Trim(),
                              parts[4].Trim(), parts[3].Trim(),
                              HexaDumpUTF16(parts[0].Trim())));
      }
    }
  }
}
// UTF16 ヘキサダンプ
private string HexaDumpUTF16(string target)
{
  var chars = target.ToCharArray();
  var sb = new StringBuilder();
  foreach (char c in chars)
  {
    sb.Append(string.Format("0x{0:X4} ", (ushort)c));
  }
  return sb.ToString().TrimEnd();
}

データ管理クラスとして CharX0213 を用意、List<CharX0213> を作成してソートします。

// 対象データ
private List<CharX0213> lstTarget = new List<CharX0213>();

// 対象ファイルロード → ソート → 結果ファイル出力
public void DoSort(string x0213_1, string x0213_2, string output)
{
  // 対象ファイルロード
  lstTarget.Clear();
  File2List(x0213_1);
  File2List(x0213_2);

  // ソート
  var sorted = lstTarget.OrderBy(x => x.Target);

  // 結果出力
  using (var sw = new StreamWriter(output, false, Encoding.UTF8))
  {
    // ヘッダ
    sw.WriteLine("文字\t面区点\t水準\tUnicode\tUTF16");
    // データ
    foreach(var item in sorted)
    {
      sw.WriteLine(string.Format("{0}\t{1}\t{2}\t{3}\t{4}",
                            item.Target, item.X0213, 
                            item.Level, item.Unicode, 
                            item.HexaDumpUTF16));
    }
  }
}
// ファイル ロード
private void File2List(string path)
{
  using (var sr = new StreamReader(path, Encoding.UTF8))
  {
    // ヘッダ
    var line = sr.ReadLine();
    // データ
    while (sr.Peek() > -1)
    {
      line = sr.ReadLine().Trim();
      var items = line.Split('\t');
      if (items?.Length >= 5)
      {
        lstTarget.Add(new CharX0213(items));
      }
    }
  }
}

public class CharX0213
{
  public string Target { get; set; }         // 文字
  public string X0213 { get; set; }          // JIS X 0213 面区点
  public string Level { get; set; }          // 第1水準, 第2水準, ...
  public string Unicode { get; set; }        // Unicode
  public string HexaDumpUTF16 { get; set; }  // UTF16 16進数

  public CharX0213(int sirial, string [] items)
  {
    if (items.Length >= 5)
    {
      Target = items[0].Trim();
      X0213 = items[1].Trim();
      Level = items[2].Trim();
      Unicode = items[3].Trim();
      HexaDumpUTF16 = items[4].Trim();
    }
  }
}

掲載ソースで作成したテストデータと、Windows 日本語カルチャ照合規則でソートした結果を GitHub にアップロードしておきました。

  • Windows 日本語カルチャ照合規則 確認
    • JISX0213-1.txt(JIS X0213 漢字1面 区点順 テストデータ)
    • JISX0213-2.txt(JIS X0213 漢字2面 区点順 テストデータ)
    • JISX0213-sorted.txt(ソート結果)

結果確認

ソート結果を確認すると、末尾にサロゲートペアが固まっています。
このことから、文字クラスとして、「非サロゲートペア」<「サロゲートペア」 で分類がされているようです。

「非サロゲートペア」は、第1水準漢字と第2水準漢字については、いくつかのイレギュラー部分はありますが、JIS X 0213 面区点順をベースとしているようです。
「サロゲートペア」については、Unicode順となっています。

ソート結果全体で、JIS X 0213 面区点順ではない部分の抽出として「ひとつ前の文字の JIS X 0213 面区点よりも、該当文字の JIS X 0213 面区点が小さい」部分をピックアップすると 851ヶ所もあります。
このようなイレギュラーで、規則性を見いだせたのは、第1水準漢字の直後に、第3水準 異体字という並び順 5ヶ所のみでした。

文字 面区点 水準 Unicode UTF16
1-27-06 第1水準 U+6BBA 0x6BBA
1-86-41 第3水準 U+F970 0xF970
1-27-07 第1水準 U+85A9 0x85A9
文字 面区点 水準 Unicode UTF16
1-45-83 第1水準 U+6B04 0x6B04
1-86-27 第3水準 U+F91D 0xF91D
1-45-84 第1水準 U+6FEB 0x6FEB
文字 面区点 水準 Unicode UTF16
1-46-26 第1水準 U+865C 0x865C
1-91-47 第3水準 U+F936 0xF936
1-46-27 第1水準 U+4E86 0x4E86
文字 面区点 水準 Unicode UTF16
1-46-64 第1水準 U+985E 0x985E
1-94-04 第3水準 U+F9D0 0xF9D0
1-46-65 第1水準 U+4EE4 0x4EE4
文字 面区点 水準 Unicode UTF16
1-47-13 第1水準 U+5ECA 0x5ECA
1-84-14 第3水準 U+F928 0xF928
1-47-14 第1水準 U+5F04 0x5F04

「非サロゲートペア」部分、第2水準漢字の末尾 JIS X 0213 1-84-06 以降は、第3水準漢字、第4水準漢字となります。
1-84-06 前後(前方1文字、後方15文字)のソート順を抜粋します。

文字 面区点 水準 Unicode UTF16
1-84-05 第2水準 U+51DC 0x51DC
1-84-06 第2水準 U+7199 0x7199
1-90-23 第3水準 U+7E8A 0x7E8A
1-91-78 第3水準 U+891C 0x891C
1-93-25 第3水準 U+9348 0x9348
1-93-14 第3水準 U+9288 0x9288
2-86-53 第4水準 U+84DC 0x84DC
1-14-25 第3水準 U+4FC9 0x4FC9
2-79-64 第4水準 U+70BB 0x70BB
1-85-21 第3水準 U+6631 0x6631
1-85-73 第3水準 U+68C8 0x68C8
2-91-03 第4水準 U+92F9 0x92F9
1-85-23 第3水準 U+66FB 0x66FB
1-84-26 第3水準 U+5F45 0x5F45
1-14-04 第3水準 U+4E28 0x4E28
1-14-08 第3水準 U+4EE1 0x4EE1
2-01-31 第4水準 U+4F00 0x4F00

画数、部首、音読みは関係なさそうですよね、、、
知識不足のため、この並び順から、規則性を見出すことはできませんでした。

自然順(エクスプローラ互換)

WIN32API - StrCmpLogicalW でソートした場合についても、Windows 日本語カルチャ照合規則と同様の結果となりました。

まとめ

Windows 日本語カルチャ照合規則、および、自然順(WIN32API - StrCmpLogicalW)で漢字をソートすると下記順序となります。

  • 非サロゲートペア
    • 第1水準漢字と第2水準漢字( + 第3水準漢字 5文字)
      • 基本的に JIS X 0213 面区点順
      • 第1水準漢字の直後に、第3水準 異体字が配置されるケース有り
        • 殺(1-27-06、第1水準)殺(1-86-41、第3水準)
        • 欄(1-45-83、第1水準)欄(1-86-27、第3水準)
        • 虜(1-46-26、第1水準)虜(1-91-47、第3水準)
        • 類(1-46-64、第1水準)類(1-94-04、第3水準)
        • 廊(1-47-13、第1水準)廊(1-84-14、第3水準)
    • 第3水準漢字と第4水準漢字
      • 規則性を見出すことはできませんでした
  • サロゲートペア
    • Unicode順
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?