LoginSignup
84
72

More than 5 years have passed since last update.

繁体字と簡体字と日本語を区別する

Posted at

前提

  • 繁体字と簡体字と日本語、それぞれ用のフォントがある。
  • 元の文章の言語はわからない。
  • でも適切なフォントを割り当てないといけない。
  • 見た目が変じゃなければオッケー(じゅうよう)

という状況のときにうまくやる方法。

繁体字とは

むかしっからある中国の文字(雑w)
(くわしくは 繁体字 - Wikipedia をどうぞ)

簡体字とは

↑繁体字むずいから簡単にしたやつ(雑w)(簡体字 - Wikipedia
でも全部の繁体字が簡化されてるわけじゃない(←じゅうよう)

日本の漢字との関係

中国語の学習には繁体字も簡体字も欠かすことができない - GIGAZINE
https://gigazine.net/news/20171022-chinese-traditional-simplified-characters/

日本語 繁体字 簡体字
三者三様
三者同一
日本語だけ違う
繁体字だけ違う
簡体字だけ違う

しかも

日本語 繁体字 簡体字

は言語間で対応してない。

Unicode における漢字

CJK統合漢字 - Wikipedia っていうやつで、要するに「中国語、日本語、朝鮮語で使われている漢字をひとまとめにした」やつ。同じみための漢字は言語問わずおなじコードポイント。ここからここまでのコードが日本語で、ここからここまでのコードが繁体字で、みたいなことにはなってない。↑の表の「作」はどの言語の文章にでてきても U+4F5C というコード。

判別するには

  1. 日本語にしかない文字(ひらがな・カタカナ)が含まれてたら → もちろん日本語
  2. 繁体字にしかない文字が含まれてたら → もちろん繁体字(↑の表の「繁体字だけ違う」パターン)
  3. 簡体字にしかない文字が含まれてたら → もちろん簡体字(↑の表の「簡体字だけ違う」パターン)

Unihan_Variants.txt

繁体字・簡体字にしかない文字のデータベースどっかにないの? → あります。

cjk - Simplified Chinese Unicode table - Stack Overflow https://stackoverflow.com/questions/4596576/simplified-chinese-unicode-table/4596760#4596760

Unihan Database っていう漢字データベースの奥の方にある Unihan.zip のなかにある Unihan_Variants.txt というやつが異体字のリストになってて、繁体字←→簡体字のペアもここに書いてある。

U+3469  kTraditionalVariant U+5138
U+346F  kSimplifiedVariant  U+3454
U+3473  kSimplifiedVariant  U+3447
U+3487  kSemanticVariant    U+511B<kMatthews

こんな感じになっていて、U+3469 の繁体字バージョンは U+5138 ですよ、と。

つーことで、↓みたいなスクリプトを書いて抽出すると、繁体字・簡体字にしかない文字リストができあがる。

# filter = 'kTraditionalVariant'
filter = 'kSimplifiedVariant' # 簡体字版がある文字=繁体字

codes = []
with open('Unihan_Variants.txt') as f:
    for line in f:
        line = line.strip()
        tokens = line.split('\t')
        if len(tokens) < 3:
            continue
        if tokens[1] == filter and tokens[0] != tokens[2]:
            codes.append(tokens[0].replace('U+', '\u'))
print('|'.join(codes))

最後の print は C# で使う正規表現用。

ようやく判定用のコード

using System.Text.RegularExpressions;


public class LanguageDetector
{

    public static string Detect(string text)
    {
        // ほんとはここでひらがなカタカナだけじゃなくて、日本語にしか使われてない漢字も含めたほうが精度あがる
        if (JapaneseKana.IsMatch(text))
        {
            return "ja";
        }

        var sc = SimplifiedChinese.IsMatch(text);
        var tc = TraditionalChinese.IsMatch(text);
        if (sc && tc)
        {
            // たまに繁体字・簡体字両方含んでるやつがあるので、そのときは多い方にする
            var scount = 0;
            var tcount = 0;
            var n = System.Math.Min(text.Length, 100);
            for (var i = 0; i < n; i++)
            {
                var t = text.Substring(i, 1);
                if (SimplifiedChinese.IsMatch(t))
                {
                    scount++;
                }
                else if (TraditionalChinese.IsMatch(t))
                {
                    tcount++;
                }
            }
            if (scount > tcount)
            {
                return "zh-cn";
            }
            else
            {
                return "zh-tw";
            }
        }
        else if (sc)
        {
            return "zh-cn";
        }
        else if (tc)
        {
            return "zh-tw";
        }

        // ここに来た時点ではまだ日本語・繁体字・簡体字どれも可能性あるんだけど、
        // どれにも含まれる漢字しか使われてないので、日本語フォントでも問題なく表示される。
        if (Kanji.IsMatch(text))
        {
            return "ja";
        }

        return "en";
    }


    static Regex JapaneseKana = new Regex(@"\p{IsHiragana}|\p{IsKatakana}");
    static Regex Kanji = new Regex(@"\p{IsCJKUnifiedIdeographs}");
    // ↓Pythonスクリプトで生成したやつをコピペ
    static Regex SimplifiedChinese = new Regex(@"\u343D|\u3447|\u3448...{省略}...\u2B6F6|\u2B6F8|\u2C88D");
    static Regex TraditionalChinese = new Regex(@"\u346F|\u3473|\u3493...{省略}...\u2A535|\u2A600|\u2A62F");

}

つー感じ。すげえでっかい正規表現になっているのでパフォーマンスが多少気にはなるのだけど、まー、たぶんだいじょぶ。

84
72
2

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
84
72