正規表現: 元号の漢数字「〇一二三四五六七八九十」にマッチさせる

正規表現で漢数字のマッチをUnicode文字クラスで一発で表現できないかと試行錯誤したことがありました。

  • 普通っぽい漢数字: 〇一二三四五六七八九十百千万億兆京
  • マニアックな漢数字: 零〇壱一弐二参三肆四伍五陸六漆七捌八玖九拾十陌百阡千萬万億兆京

でも結局、ユースケースに応じて文字セット[]でべた書きプラスアルファするよりないというのが私なりの結論です。

日本の元号の漢数字にマッチさせる

  • 例: 日本の元号(明治以降)の漢数字にマッチ: /(?<=明治|大正|昭和|平成)[二三四五六七八]?[一十]?[元一二三四五六七八九十〇](?=年)/(regex101

ご覧のとおり、「平成元年」だの「平成一〇年」「平成三〇年」というパターンにも対応しています。

一見冗長に見えるかと思いますが、一応以下のように文字セット[]を桁ごとに分けて精度を高め、かつメンテしやすくしているのがポイントです。

  • [二三四五六七八]?: 十の位の最初の桁
    • は現実的でないと思ったので入れていません
    • 七八は将来に備えて入れてみましたが、今のところは出現していませんのでやりすぎかもしれません
  • [一十]?: 十の位が単独の場合の桁
  • [元一二三四五六七八九十〇]: 一の位

もっとも上の場合「平成八一〇年」などの非現実的な漢数字にもマッチしてしまいますが、これらを除外すると可読性が落ちるばかりなのでやっていません。

なお、「年号の漢数字だったら以下のように[元一二三四五六七八九十〇]+(?=年)ぐらいで十分じゃね?」とお思いになるのももっともです。こちらは「平成〇一八九十年」のような非現実的な漢数字にいくらでも長くマッチしますが、お好きな方をどうぞ。

  • 例: 雑な年号漢数字マッチ: /[元一二三四五六七八九十〇]+(?=年)/(regexp100

私は*+を使うマッチが個人的にキライなので、2番目にするなら+{1, 3}にすると思います。

数値にマッチするUnicode文字カテゴリ

Unicodeの文字クラスの文字カテゴリには、「数値」を表すNというカテゴリがあります。Nはその下にいくつかのサブカテゴリがあります。

実はN単体のカテゴリというものはUnicodeの文字カテゴリにはないのですが、正規表現では[\p{N}]とすると以下のNdNlNoのすべてをまとめて表現できます。

  • Nd: 数字で表す数値(Decimal Number
    • 半角数字([0123456789]
    • 全角数字([0123456789]
    • アラビア文字やクメール文字の数値など
    • その他多数
  • Nl: 文字で表す数値(Letter Number
    • ローマ数字(など)
    • その他多数
  • No: その他の数値(Other Number
    • 分数(¼など)
    • 上付き下付き数値(¹など)
    • 外字由来の装飾数字(など)
    • 古代の数字(𐄡: エーゲ文字の900など)
    • 漢文訓読用数値
    • その他多数

もっとも、私の場合N系の文字カテゴリが正規表現で必要になったことはありませんが。

漢数字のだけは数値扱い

[\p{N}]でありとあらゆる数値にマッチすると書きましたが、いわゆる漢数字の中で[\p{N}]にマッチするのは(漢数字の〇)だけです。以下をご覧ください。

  • 例: あらゆる数値文字にマッチする/[\p{N}]/(Regex101

考えてみれば、漢数字一二三四五六七八九十百千万億兆京は人名地名などにも使われるのですから数字扱いするのは無理がありますね。

紛らわしい「漢文訓読用の漢数字」

と思っていたら、先ほどのNo: その他の数値(Other Number)の中に漢数字としか思えないものがあるじゃありませんか。


compart.comより

思わず五より大きい漢数字を探しそうになってしまいました。

しかし種を明かせば、これは「Kanbun」(漢文)というUnicodeブロックです。以下を見ればおわかりのように、日本で漢文の読み下し(訓読)用に漢文の横に付けられる「訓点」と呼ばれる特殊な文字です。この「」は例外的に数値に分類されているのです。


compart.comより

こうして眺めてみると、訓点はどことなく古代に狂い咲いたマークアップ言語のように思えてきませんかそうですか。本文で一度読んだ文字は二度と読まれないという性質から、チューリング不完全なのは確かだと思いますが。

この訓点を使う人は非常に少ないと思われるので普段はそこまで気にする必要はないと思いますが、[\p{N}]のような広大な文字セットを使うときにはふと思い出してみるとよいと思います。

参考: 漢文訓読 - Wikipedia

関連記事

はじめての正規表現とベストプラクティス#1: 基本となる8つの正規表現

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

夏のTechRachoフェア2019

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ