激闘TeX:正規表現という名の沼
正確にはTeXの話題ではないんですが、ルビ振りの時に迷った(今も迷ってる)ので書いておきます。他形式からの一括検索・置換について。
青空文庫・カクヨム・小説家になろう等、各種形式を検索パターンに押し込むのは分かりやすくかつ詳細なこちらの記事を全面的に参考にさせていただきました。多謝。
各種小説投稿サイトのルビ記法をJavaScriptで実現する - Qiita
その上でTeX形式に置換していきます。なおこの記事内においては煩雑さを避けるため青空文庫形式限定で表現します。
pxrubricaパッケージにおいて、和文へのルビ振りと欧文へのルビ振りは\ruby
と\aruby
命令として厳密に区別されています。それに沿うために、和文と欧文の置換パターンは分けることにしました。よって青空文庫のルールに従って、欧文の検索・置換パターンは次の2つになります。
①長いフレーズなど、親文字の範囲が明確に特定できず、全角縦棒で範囲を指定してあるもの
|([\w\p{P}\s]+)《(.+?)》
→ \\aruby{\1}{\2}
②単語などアルファベットのみで構成され、空白等で区切りが明確に分かっているもの(縦棒を省略できる)
(\w+)《(.+?)》
→ \\aruby{\1}{\2}
ところがここで壁にぶち当たりました。①のパターンは、フレーズにヒットさせるために単語構成文字(アルファベット、数字、アンダースコア)\w
にスペース\s
と約物\p{P}
を含めたものなんですが、これで検索をかけてみるとこうなります。
2行目にもヒットしてほしいのに無視されてます。これは後半のルビ部分を外してみると分かりやすいんですが、
2行目にフランス語のç(セディーユつきc)が含まれているからヒットしないんですね。拡張アルファベットはアルファベットとみなされないらしいです。②のパターンでも、アクセント・ウムラウトつきアルファベットが含まれる単語はヒットしません。 おのれ……。
まあ\w
という表現がベテランの、つまりASCIIを基準にしているものなので仕方ありません。仕方ないのでここは頼れる助っ人・Unicode文字プロパティの力を借りましょう。アルファベットの属するスクリプトはLatin、そして数字を含まないので、\d
で補ってやってこうなります:|([\p{Latin}\d\p{P}\s]+)《(.+?)》
すると……
セディーユはいいんですが、恐ろしいことに一番下の全角アルファベットと中黒P・L・M
までヒットしてしまいました。これは全角縦書きなのでarubyではなくruby扱いしたい。というか"したい"レベルではなくしなければなりません。ここに\aruby
を振っちゃうとこんな惨事が起きます。
うーんどうしよう……\p{Latin}
を\p{Lu}\p{Ll}
に差し替えるなどいろいろ試してみましたが、とりあえず現時点で拡張アルファベットにはヒットして全角英数字にはヒットしない正規表現というのは私には見つけられませんでしたorz
かくなる上は全角にもヒットしてしまう方か英語以外を拾えない方か、どちらかを採用した上で運用に気をつけるしかありません。Meryに青空構文を入れて使っていれば拾い残しは可視化できるので、\w
を使う方が不用にarubyを振る危険性がなく安心かとは思うんですがどうなんでしょう。p{Latin}
の方で全部拾って、一つ一つチェックして必要なところは飛ばしながら置換する、というのも網羅的でいい気がします。
とりあえずサイトの記事ではどちらも載せて、英語だけ使う人は\w
の方でと書いておきました。もしいい手が浮かんだら変更します。