Unicodeで「漢字」の正規表現

改訂:2017/07/22
Unicode 10.0に合わせて書き直し。正規表現を簡易にしようとしてやりすぎていたのを修正。

改訂:2023/03/21
U+30000以降を追加。InDesignの正規表現を追記。


正規表現で漢字の範囲指定をする場合、Unicodeではどうするかが悩ましいところです。

Unicodeの漢字の範囲として [一-龠] にしている例を見かけます。しかしこれは旧規格JIS X 0208の漢字が含まれる範囲をUnicodeの中から切り出しているだけです。互換漢字ブロックをまるごと取りこぼしているので、WindowsのシフトJIS(CP932)の拡張漢字に当たるものが含まれていません。現規格JIS X 0213の第3・第4水準漢字も考慮されていません。簡易な範囲指定だとしても、新常用漢字の「𠮟」が含まれておらず、今から見るとあまりに時代遅れです。

Unicodeのすべての漢字の正規表現 その1

環境によってはUnicodeスクリプトの \p{Han} が使えます。対応するコードポイントの一覧はこちらで確認できます。
※リンク先はUnicodeの最新のバージョンではない場合があるので注意してください。
UnicodeSet で \p{Han} の対応コードポイント一覧を表示

Unicodeのすべての漢字の正規表現 その2

\p{Han} が使えない環境は普通にあります。使えたとしてもUnicodeの最新バージョンに対応しているとは限りません。しっかりマッチさせたい場合は、範囲指定をするしかありません。その際、漢字はUnicodeの中であちこちに分散しているので、シンプルな範囲指定は不可能です。

Unicodeの漢字の内訳は以下になります。

※コードポイントの範囲は未定義箇所を含めています。\p{Han} に含まれるハングルの数字(12文字)は除外しています。Unicodeのバージョンが上がっても対応できるようにBMP外はU+2FFFFまで含めています。

2E80..2FDF CJK部首補助+康熙部首
3005 々(漢字の踊り字)
3007 〇(漢数字のゼロ)
303B 〻(漢字の踊り字)
3400..4DBF CJK統合漢字拡張A
4E00..9FFF CJK統合漢字
F900..FAFF CJK互換漢字
20000..3FFFF CJK統合漢字拡張B〜G+CJK互換漢字補助+CJK統合漢字拡張H+念のためU+3FFFFまで

これをまとめると、下記になります。いかがでしょうか。

[\x{2E80}-\x{2FDF}々〇〻\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{20000}-\x{3FFFF}]

InDesign CS3~2023(18.1)

InDesignの漢字のワイルドカード「~K」は使いものにならないので、上記の正規表現を使った方がいいでしょう。

InDesign 2023(18.2)~

「~K」が改善されたので、短くできます
[\x{2E80}-\x{2FDF}々〇〻~K\x{30000}-\x{3FFFF}]

20件のコメント

  1. JavaScriptの文字列は16ビットUnicodeで表現される仕様になっており、BMPに含まれない文字はサロゲートペアで表現されます。このため、/\u20000-\u2FFFF/ ではなく /[\uD840-\uD87f][\uDC00-\uDFFF]/ としないとヒットしないのです。
    参照:http://liosk.blog103.fc2.com/blog-entry-72.html あたり

  2. [々〇〻\u3400-\u9FFF\uF900-\uFAFF\U00020000-\U0002FFFF]

    InDesign CS3 の JavaScript で試したら、↑これでヒットしました。
    いいのかな? 大丈夫かな? 自分で使いながら様子を見てみます。
    ちなみに仕事では「★愛★あい★」といったルビ仕込みのテキストを InDesign 上で選択する JavaScript を作って使ってます。なので漢字の正規表現が必要なのです。

  3. \UhhhhhhhhはInDesignの独自拡張みたいです。Webブラウザ(少なくともIE8, Firefox 3.6.4build1, Opera 10.52 for Win, Safari 4.0.5 for Win, Chrome)ではサポートされされていませんでした。
    ECMA-262の仕様では文字列は単なる符号なし16bit整数の配列ということになっていて、サロゲートペアについても何もしてくれません。自分でエンコードする必要があります。
    (?:[々〇〻\u3400-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF])

  4. えむけいさん、検証とコメント、ありがとうございます!

    > \UhhhhhhhhはInDesignの独自拡張みたいです。
    いくら調べてもこれでいいという情報がないので心配でしたが、
    独自拡張ということなら大丈夫そうですね。
    (念のため、時間が空いたときにもうちょっと検証してみます)

    > (?:[々〇〻\u3400-\u9FFF\uF900-\uFAFF]|[\uD840-\uD87F][\uDC00-\uDFFF])
    なるほど〜「前後のコードポイントの組み合わせ」にするんですね!

  5. あ〜〜! はげしく勘違いしてた!!
    私が InDesign でやっていたのは↓コレでした。

    var reg_Oyazi = “[々〇〻\u3400-\u9FFF\uF900-\uFAFF\U00020000-\U0002FFFF]+”;
    var reg_Rubizi = “[  ぁ-ヿ*]+”;
    var my_find_obj = {findWhat:”★”+reg_Oyazi+”★”+reg_Rubizi+”★”};

    まさに独自拡張…

    で、これで選択した箇所を JavaScript でルビにするのに親字の文字数をかぞえる必要があって、そうするとサロゲートペアが邪魔なので別の文字に置換しなくちゃいけなくて、

    oyazi = oyazi.replace(/(?:[\uD840-\uD87F][\uDC00-\uDFFF])/g,”親”);
    var oyaziCount = oyazi.length;

    これでバッチリ。えむけいさん、ありがとう!

  6. anony さん
    「ハングル語」は間違いで「ハングル」が正しいということですか。
    直しましたー

  7. 先日「~K」を使って失敗しました。もっとはやくこの記事に出会っていれば……。次回からはこちらの正規表現を使わせて頂きます。貴重な情報ありがとうございます。

  8. 有用な情報、ありがとうございます。
    本論とは関係ない部分ですが、易経は四十六卦ではなくて、六十四卦ではないでしょうか。

  9. 恐れ入ります。こちらの正規表現を自作クロームエクステンションで利用させていただいてもよろしいでしょうか。

  10. yoshさん、全然OKです。お好きにお使いください。
    あ、よく見たら今はCJK統合漢字拡張E~Fもあるので、追加しなくちゃ…

  11. ありがとうございます。利用させていただきます。大変参考になりました。

  12. 改訂しました。
    ・CJK部首補助+康熙部首を除外していたのを思い直して追加。
    ・易経の六十四卦を含めていたのを思い直して除外。

  13. > JSはUTF-16なので、正規表現にサロゲートペアの対策が必要です。

    最近の環境(ES2015 以降)では Unicode フラグ “u” が使えますので、サロゲートペアなどというものを意識することなくコードポイント単位で処理できます。

    https://blog.jxck.io/entries/2017-03-02/unicode-in-javascript.html#%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE

    ……という点に言及があると親切かと思います。

  14. すばらしいです。
    利用させていただきます。
    感謝!
    すごく助かりました。

  15. こんにちは。戦前の本からの引用をするのですが、漢字部分を旧字体のフォントで、それ以外のひらがな部分をフリーフォントの古風なものにしたいと思っています。文章自体に踊り字もたくさん含まれるため、全体をかなで使いたいフリーフォントに置き換えてから、漢字の部分だけをワイルドカードで指定し、置換をしたいのです。

    wordの「高度な検索と置換」で「ワイルドカードを使用する」と指定し、上に記載がある [\x{2E80}-\x{2FDF}々〇〻\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{20000}-\x{3FFFF}] で範囲指定をしましても、ワイルドカードが不正と出て実行できませんでした。 [一-龠]  であれば実行できます。恐れ入りますがもし対処方法などございましたらお教えください。

  16. Wordのワイルドカードは正規表現のようなものであって、通常の正規表現とは異なるものです。とくに \x[] で文字コードを指定する書式には対応していないようです。
    Webブラウザでは互換漢字が統合漢字に勝手に変えられてしまうので、それを防ぐために \x[] を使っています。この箇所を \x[] ではなく、その文字にすれば、もしかするとWordで使えるかもしれません。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です