SRELLの今後とregexのUnicode対応

目次

regexのUnicode対応に向けて

 現在のSRELLは「C++のregexがUTF-8, UTF-16, UTF-32にも対応していたらおそらくこんな感じではないか」あるいは「こんな感じであってほしい」というコンセプトの下に作られているのですが、C++20でchar8_tが導入されたことにより、templateの特殊化を利用すればUTF-8, UTF-16, UTF-32で処理をし分けるという方法が使えるようになったことを踏まえて、この辺りでSRELL相当の機能をregexにフィードバックすべく提案書をC++の委員会に出してみることにしました。

 委員会メンバーの方から聞いた話によりますと、ライブラリの拡張に携わっている人たちは現状のregexに不満を感じていて、「いっそのこと別の何かに置き換えてしまってregexはdeprecateしたい。P1433のCTRE(ソースコンパイル時に正規表現文字列から直接その表現専用の照合用コードを作ってしまうライブラリ。凄まじく速い。ただしランタイムにならないと正規表現文字列が判明しないような場合には使えない)がその『別の何か』になったら良いな」と考えている人もいるようです。
 一方Unicodeやテキスト処理の専門部会であるSG16は正規表現のことにそれほど関心がないようで、「Unicode対応を進めてゆく中で正規表現のこともいずれ何とかしたい。その場合はUTS #18が典拠に作業を進めたい」という考え方のように見受けられます。率直に言ってライブラリの拡張作業部会周辺にいる人たちより「regexを何とかしたい度合い」は低いという印象です。
 いずれにしましてもregexを改良すべく動いている人はいないようですので、このままですとC++23はおろかC++26やC++29になってもregexの今のまま、ということになりかねません。

 提案書の行き着く先としては4通り考えられます。1つ目は「代理でプレゼンしてくれる人が現れずそのままrejectされてしまう」というケース、2つ目は「プレゼンしてくれる人が現れてライブラリの作業部会で議論されるものの、多数の支持を得られずrejectされてしまう」ケース、3つ目は「委員から概ね支持されるも強く推してくれる人がいないことから優先度が下げられ、そのうち推進力を失って有耶無耶になってしまう」ケース、そして4つ目は「紆余曲折を経て最終的には受理される」というケースです。

 このうち最後の可能性が実現した暁にはC++標準ライブラリのregexで今のSRELLと同じようなことが出来るようになりますので、SRELLの需要はほぼなくなるものと予想しています。そうなった際にSRELLをどうするかは今のところまだ決めていませんが、仮に続けるとした場合、長期的にはregexから離れてもっと使いやすいclassデザインに改めるかもしれません。

 問題は残りの3つのどれかになってしまった場合です。現行の<regex>のクラスデザインを維持してUnicode対応を行う場合、「regexをUTF-32対応にして、UTF-8とUTF-16とについてはUTF-32に変換するイテレータのようなものを噛ませて使う」か「テンプレートの特殊化を使ってUTF-8, UTF-16, UTF-32を処理し分ける」か、それぐらいしか現実的な選択肢はないのではないかと個人的には考えているのですが、前者は既にrejectされています。その上でもし今回試してみる後者の方法もC++委員会のライブラリ拡張作業部会の関心を引かなかったとなりますと、既にregexは多くの委員から見捨てられてしまっていて「regexはもう良いから別の正規表現ライブラリの提案を誰か持ってきてくれ」という空気が支配的になっている可能性がいよいよもって濃厚になってきます。
 しかしregexの完全代替となりうるものは今のところまだ提案されていません。従いましてC++規格にUnicode対応の正規表現ライブラリが含まれるようになるのは相当先のことになってしまうことが予想されます。
 またSRELLに関しましても、現行のregexが既に委員会から見捨てられているのだとしますと、そのクラスデザインを踏襲する理由もなくなってきます。そのため、この場合もregexから離れてもっと使いやすいclassデザインに改めるかもしれません。

 C++の委員会はこれからしばらくの間、C++20のドラフトに対して各国NB(National Bodyの略。いわゆる標準化団体)から寄せられたコメントに対応することを優先するため、11月のベルファスト会議と来年2月のプラハ会議では新規の提案に時間を割くことがあまり出来ないだろうと聞いています。プレゼンしてくれる方がうまく現れてくださるようであれば、来年6月のヴァルナ会議あたりで議論してもらえるかもしれません。

lookbehindの逆行限界を指定する方法

 SRELLのversion 2.300以降には、lookbehindの逆行限界を指定するための手段としてmatch_lblim_availフラグとmatch_resultsクラスにBidirectionalIterator lookbehind_limitメンバとが追加されています。しかしこのような指定は本来であれば、regex_search()に引数として渡すほうが自然です。
 にもかかわらずそうしなかったのは、引数の渡し方に次の2通りが考えられるためです。

//  渡し方1
bool regex_search(
    BidirectionalIterator first,
    BidirectionalIterator last,
    BidirectionalIterator lookbehind_limit,
    match_results<BidirectionalIterator, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);

//  渡し方2
bool regex_search(
    BidirectionalIterator lookbehind_limit,
    BidirectionalIterator first,
    BidirectionalIterator last,
    match_results<BidirectionalIterator, Allocator>& m,
    const basic_regex<charT, traits>& e,
    regex_constants::match_flag_type flags = regex_constants::match_default);
	

「渡し方1」はlookbehindの逆行限界を「通常の [first, last) への追加で渡すもの」という考え方に基づいた指定方法です。「渡し方2」は、3つのiteratorを昇順に並べたものです。「[lookbehind_limit, last) を検索対象範囲と見なし、その範囲内の first の位置から検索を開始する」という考え方に基づくとするなら、こちらのほうが直感的と言えるかもしれません。

 C++の委員会への提案書では「渡し方1」のほうを示してありますので、もし提案がこのまま受理されたりあるいは拒否されたりした場合には、SRELLにも渡し方1のオーバーロードを追加する予定です。ただもし議論の過程で渡し方2のほうが好ましいということになれば、SRELLにも2のオーバーロードを追加することになります。

 これら2つは引数の型の並びがまったく同じですのでコンパイラには区別がつきません。そのため委員会の好みを聞く前にどちらかの渡し方をSRELLに先行実装してしまいますと、後々非互換の仕様変更を行わなくてはならなくなってしまう可能性があります。
 そうなるのを避けるため、現時点ではmatch_lblim_availフラグとmatch_resultsクラスのBidirectionalIterator lookbehind_limitメンバとを使って指定するという方法を採っています。

WG21 Belfast会議

 2019年11月に開かれたWG21のベルファスト会議にて先述の「regexのUnicode対応」提案も少し議論されました。
 当初はLEWGI(ライブラリの追加拡張提案について議論する部会。従来はLWGが本選、LEWGが予選のような形だったが、近年提案が増えてLEWGだけでは捌ききれなくなってきたためかLEWGの下にLEWGIが設けられた)でも議論するための時間を確保してくださっていたのですが、提案者である自分が現地に行って直接プレゼンできないことと、SG16が「先にうちで議論したい」と述べたことなどから今回の会議ではSG16のみでの議論となりました。

 結果は概ね予想通りで、SG16としては「今さらregexを良くするために注力したくない。我々としてはCTRE (P1433) を補完するような形のライブラリが欲しい」とのことでした(註・CTREはランタイムにならないと正規表現パターンが確定しないケース、例えばgrepのようなツールやエディタの正規表現検索機能などには使えないので、その部分でregexの代わりとなるものが欲しいという意味)。
 将来CTREベースの標準ライブラリが出来ることを前提としている辺りに少し危なっかしさを感じるのですが、当のP1433は2019年2月のKona会議で議論されたのを最後に改訂版が提出されていません。P1433は新規提案で今はまだLEWGIの段階にあり、この後LEWG、LWGと上がってゆく中で仕様の修正を求められることも予想されますので、先はまだ長いのではないかと個人的には感じています。

 ライブラリに対する提案の採否を決めるのはLWG-LEWG-LEWGIのラインですので、今回のSG16の判断が提案の行く末を直接左右するようなことはないと受け止めています。ただ今後、LEWG/LEWGIにおける判断材料の一つとして使われる可能性は否定できません。
 SG16は事実上「Unicode対応版のregexは要らない」と言った以上、この度のregex提案について再度議論することはないでしょうから、次なる焦点はLEWGIがどのような判断を下すかです。早ければ次回のプラハ会議(2月)で、時間がなければその次のヴァルナ会議(6月)で議題に上ると予想しています。