メインコンテンツへスキップ
  1. blog/

Noto Sans JP, SC で SC を優先表示する漢字 (复,关,门,etc.)

Web China Graphic
くろえい
著者
くろえい
高専生.ガジェット、中国やお出かけに関心あり.1人旅は移動式の引きこもり.たまにお勉強.「すごい人」にはなれなかったが、日々奮闘しております
目次

はじめに
#

フォントファミリーを 'Noto Sans CJK JP''Noto Sans JP','Noto Sans SC' と指定した場合、 主に簡体字中国語で用いられる漢字の表示が不適切になる場合がある.

例:

  • 我们必须尽快复习功课。
  • 请记得出门时关灯。

复, 关, 门 ではなく 复, 关, 门 と表示されるべきだ.

SC を優先表示する漢字一覧
#

私の主観に基づいて、中文简体用のフォントを優先表示させるべき漢字を列挙した.

次の CSS にて font-family: 'Noto Sans SC'; で登場する順である.

Noto Sans JP Noto Sans SC Unicode
U+8fc2
U+6c72
U+8fc4
U+4e2b
U+8292
U+8fc1
U+526a
U+573e
U+7a97
U+542f
U+6781
U+9002
U+8fbe
U+590d
U+8fd0
U+5173
U+7c7b
U+95e8
迂汲迄丫芒迁剪圾窗启极适达复运关类门

CSS における解決法
#

HTML の <head> に次のコードが埋め込まれていることとする.

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100..900&family=Noto+Sans+SC:wght@100..900&display=swap" rel="stylesheet">

CSS にて、SC を優先表示する漢字を集めたフォントファミリー Noto Sans SC partial を次のように定義する.

ただし、src に記載されたフォントのURLは本記事執筆時のものである.更新される可能性があるため、先程の CSS を確認すること.

/*
    JP より先に SC を表示させたいもの
    Unicode Converter: https://tech-unlimited.com/escape-unicode.html
    see: https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100..900&family=Noto+Sans+SC:wght@100..900&display=swap
*/
/* [33] */
@font-face { /* 迂 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.33.woff2') format('woff2');
    unicode-range: U+8fc2;
}
/* [61] */
@font-face { /* 汲 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.61.woff2') format('woff2');
    unicode-range: U+6c72;
}
/* [100] */
@font-face { /* 迄 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.100.woff2') format('woff2');
    unicode-range: U+8fc4;
}
/* [104] */
@font-face { /* 丫 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.104.woff2') format('woff2');
    unicode-range: U+4e2b;
}
/* [109] */
@font-face { /* 芒, 迁 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.109.woff2') format('woff2');
    unicode-range: U+8292, U+8fc1;
}
/* [111] */
@font-face { /* 剪, 圾 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.111.woff2') format('woff2');
    unicode-range: U+526a, U+573e,;
}
/* [113] */
@font-face { /* 窗 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.113.woff2') format('woff2');
    unicode-range: U+7a97;
}
/* [114] */
@font-face { /* 启 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.114.woff2') format('woff2');
    unicode-range: U+542f;
}
/* [115] */
@font-face { /* 极, 适 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.115.woff2') format('woff2');
    unicode-range: U+6781, U+9002;
}
/* [116] */
@font-face { /* 达 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.116.woff2') format('woff2');
    unicode-range: U+8fbe;
}
/* [117] */
@font-face { /* 复, 运 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.117.woff2');
    unicode-range: U+590d, U+8fd0;
}
/* [118] */
@font-face { /* 关, 类, 门 */
    font-family: 'Noto Sans SC partial';
    src: url('https://fonts.gstatic.com/s/notosanssc/v37/k3kXo84MPvpLmixcA63oeALhLOCT-xWNm8Hqd37g1OkDRZe7lR4sg1IzSy-MNbE9VH8V.118.woff2') format('woff2');
    unicode-range: U+5173, U+7c7b, U+95e8;
}

フォントファミリーは次のように指定する.

font-family: 'Noto Sans SC partial','Noto Sans JP','Noto Sans SC';

調査方法
#

自分でフォントを比較したい人向けに、手順を載せておく.

  1. Noto Sans JP と Noto Sans SC 両方に含まれる漢字を抽出
  2. 両者間でのフォントの違いを比較するために一覧表を作成
  3. 自身の主観に基づいて、SC を優先表示する漢字を列挙
    1. 漢字の見た目は日本語を優先する
    2. 次を満たすものを候補とする
      • 日本語よりも中国語でよく使われている
      • 見た目が日本語より中国語のほうが良い
    3. 候補に挙がった漢字のうち、簡体字が存在するものは除去する

インストール
#

Python 3.8 以上がインストールされていること.(cf. User documentation)

pip install fonttools

フォントのダウンロード
#

  1. https://fonts.google.com/noto
  2. 「Noto Sans Japanese」と「Noto Sans Simplified Chinese」を「Get Font」
  3. 👜 https://fonts.google.com/selection から「Download all」

cmap テーブルを出力
#

ファイルのパスは適宜変更すること.

ttx -t cmap NotoSansJP-VariableFont_wght.ttf
ttx -t cmap NotoSansSC-VariableFont_wght.ttf

指定したファイルと同じディレクトリに .ttx ファイルが生成される.

Unicode の取り出し
#

生成された各 .ttx について、Unicode のみ抽出する.

Visual Studio Code で .ttx を開き、正規表現を用いた置換を行う.

  • Find

    .*code="0x([0-9A-Fa-f]+).*
    
  • Replace

    U+$1
    

Unicode 以外の行は削除する.

  • Find

    ^(?!U\+).*\n
    
  • Replace (なし)

5桁未満の Unicode はゼロ埋めする.後でソートして重複を削除するためである.

  • Find

    U\+([0-9A-Fa-f]+)
    
  • Replace

    U+0000$1
    
  • Find

    U\+0*([0-9A-Fa-f]{5,})
    
  • Replace

    U+$1
    

共通する文字を抽出
#

Noto Sans JP と Noto Sans SC 両方に含まれる文字の Unicode を抽出する.

grep を用いる.Windows では Git Bash や WSL で利用できる.

grep -x -f NotoSansJP-VariableFont_wght.ttx NotoSansSC-VariableFont_wght.ttx | sort | uniq > Noto-Sans-JP-SC-common-codes.txt

一覧表を作成
#

Visual Studio Code で Noto-Sans-JP-SC-common-codes.txt を開き、正規表現を用いた置換を行う.

  • Find

    U\+0*([0-9A-Fa-f]+)
    
  • Replace

        <tr><td>&#x$1</td><td>&#x$1</td><td><code>U+$1</code></td></tr>
    

次の内容の index.html を作成する.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <style>
        @font-face {
            font-family: 'Noto Sans JP';
            src: url(NotoSansJP-Regular.ttf);
        }
        @font-face {
            font-family: 'Noto Sans SC';
            src: url(NotoSansSC-Regular.ttf);
        }
        tr > td:first-child {
            font-family: 'Noto Sans JP';
            font-size: xxx-large;
        }
        tr > td:nth-child(2) {
            font-family: 'Noto Sans SC';
            font-size: xxx-large;
        }
    </style>
</head>
<body>
<table>
    <tr>
        <th>Noto Sans JP</th>
        <th>Noto Sans SC</th>
        <th>Unicode</th>
    </tr>
    <!-- 先程の正規表現で得たコードをここに貼りつける -->
</table>
</body>
</html>

index.html が入っているのと同じディレクトリに NotoSansJP-Regular.ttfNotoSansSC-Regular.ttf を配置する.

あとは人力でがんばれ.

参考
#