upLaTeX で l3regex の 16 進コードによるマッチができない

upLaTeX で l3regex の 16 進コードによるマッチができない

- ya ra の投稿
返信数: 4

expl3 を利用して (U+3042) が \x{3042} にマッチするか確かめる関数を upLaTeX で処理するとエラーになります。(LuaLaTeX や XeLaTeX ではエラー無く処理される)

upLaTeX でもこれがエラー無く処理できる方法はあるでしょうか。

バージョン

e-upTeX 3.141592653-p4.1.1-u1.30-230214-2.6 (utf8.uptex) (TeX Live 2024)
kpathsea version 6.4.0
ptexenc version 1.4.6
Copyright 2024 D.E. Knuth.
There is NO warranty.  Redistribution of this software is
covered by the terms of both the e-upTeX copyright and
the Lesser GNU General Public License.
For more information about these matters, see the file
named COPYING and the e-upTeX source.
Primary author of e-upTeX: Japanese TeX Development Community.

再現

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{expl3}
\begin{document}

\ExplSyntaxOn

\regex_match:nnTF
{ \x{3042} }
{ あ }
{ True }
{ False }

\ExplSyntaxOff

\end{document}

該当するエラーメッセージ

 Use of \??? doesn't match its definition.
<argument> \???
                 ! LaTeX Error: Character code ##1 too large in \x{##2} regex.
l.9 { あ }

TeX ファイルと upLaTeX で実行した際のログファイルを添付します。


一方で、\x{0042} 等に変更するとエラー無くうまくいきます。

このことを踏まえて少し確かめてみると、\x{hh} 形式が使えないと言うよりは upLaTeX で \x{hh}\x{00FF} までしか使えないような雰囲気でした。

ya ra への返信

Re: upLaTeX で l3regex の 16 進コードによるマッチができない

- t tk の投稿

\x{} というのは uptex のプリミティヴでも euptex のプリミティヴでもなく、どこかで実装されているマクロだと思います。
想像するに expl3 のどこかで定義されていて、LuaLaTeX や XeLaTeX では正しいが eupTeX 向けには正しくない状況になっているものと思います。

t tk への返信

Re: upLaTeX で l3regex の 16 進コードによるマッチができない

- ya ra の投稿
t tkさま、ご回答ありがとうございます。

ユーザー側で対応できそうではありませんね…。expl3 が対応することを待ちたいと思います。
ya ra への返信

Re: upLaTeX で l3regex の 16 進コードによるマッチができない

- wryz77 の投稿

同様のケースに遭遇したので,私の理解の範囲で調べてみました。結論としてはやはり,ユーザー側で対応できる範疇ではなさそうですが・・・

以下,expl3-code.tex の中身を見ていきます。まず,該当のメッセージは次のように定義されています。

\msg_new:nnn { regex } { x-overflow }
  {
    Character~code~##1~too~large~in~
    \iow_char:N\\x\iow_char:N\{##2\iow_char:N\}~regex.
  }

このエラーが呼び出されるのは,\__regex_escape_x_end:w という関数の内部です。

\cs_new:Npn \__regex_escape_x_end:w #1 ;
  {
    \int_compare:nNnTF {#1} > \c_max_char_int
      {
        \msg_expandable_error:nnff { regex } { x-overflow }
          {#1} { \int_to_Hex:n {#1} }
      }
      {
        \exp_last_unbraced:Nf \__regex_escape_raw:N
          { \char_generate:nn {#1} { 12 } }
      }
  }

この関数の中に\c_max_char_int という整数値がありますが,その定義は「LuaTeX/XeTeX の場合は "10FFFF,そうでない場合は "FF」というものです。よって,upTeX では文字コードが "FF より大きい文字に対して関数 \__regex_escape_x_end:w はエラーを返すことになります。

では,expl3 のコードを修正し,\c_max_char_int の定義を upTeX に対応するように変更すればよいのかというと,そうでもありません。

\__regex_escape_x_end:w の定義の中に \char_generate:nn {#1} { 12 } とありますが,これは実質的には \Ucharcat #1 12 ,つまり文字コード #1,カテゴリーコード 12 の文字トークンに展開される,というものです。

しかし,pTeX では \Ucharcat は欧文文字しか生成できません。また,upTeX では \Ucharcat で和文文字を生成できますが,\Ucharcat で指定できるカテゴリーコードは 16 ~ 20 に限られます。一方,\char_generate:nn では 13 以上のカテゴリーコードは指定できません。

つまり,今回のケースは最終的に,pTeX/upTeX と expl3 との間での文字トークンの扱いの齟齬,という点に行き着くと思っています。

【余談】私が今回のケースを発見したのは,TeX Live 2024 において pTeX/upTeX 上で glossaries.sty を読み込もうとしたときに同様のエラーが出たのがきっかけでした。

wryz77 への返信

Re: upLaTeX で l3regex の 16 進コードによるマッチができない

- 本田 知亮 の投稿
処理を通すために下のようにその場限りの書き換えをすると

\regex_match:nnTF
{ \x{3042}い }
{ あいうえお }
{ True }
{ False }

はTrueに,「あかいうえお」すると Falseになって
なんとなく正しく動いている雰囲気にはなります.

\__regex_escape_x_end:w の最後でカテゴリコード12決め打ちのところを
#1の範囲に応じて12以外にできれば
もしかすると突破できる?
いまのupTeXのこのあたりのkcatcodeの設定がどうなってるのか分かってないですし,
このあたりのexpl3のコードもまるで読めないので
なんで通るのかもさっぱりです(正しい?偶然?)

%----------------------------------------
\documentclass{article}

\ExplSyntaxOn

\cs_set_eq:NN \c_max_char_int \relax
\int_const:Nn \c_max_char_int {"10FFFF}%%範囲を広げる

\cs_set:Npn \__regex_escape_x_end:w #1 ;
  {
    \int_compare:nNnTF {#1} > \c_max_char_int
      {
        \msg_expandable_error:nnff { regex } { x-overflow }
          {#1} { \int_to_Hex:n {#1} }
      }
      {
% #1 には文字コードがdecimalで入ってきている
        \exp_last_unbraced:Nf \__regex_escape_raw:N
          { \char_generate:nn {#1} { 17 } } %%ここを12以外にしてみる
      }
  }

\cs_set:Npn \__char_generate_aux:w #1 ; #2 ;
  {
    \if_int_odd:w 0
        \if_int_compare:w #2 < 1  \exp_stop_f: 1 \fi:
        \if_int_compare:w #2 = 5  \exp_stop_f: 1 \fi:
        \if_int_compare:w #2 = 9  \exp_stop_f: 1 \fi:
        \if_int_compare:w #2 > 20 \exp_stop_f: 1 \fi: \exp_stop_f:%%カテゴリコードの範囲を20まで広げてみる
      \msg_expandable_error:nn { char }
        { invalid-catcode }
    \else:
      \if_int_odd:w 0
        \if_int_compare:w #1 < \c_zero_int 1 \fi:
        \if_int_compare:w #1 > \c_max_char_int 1 \fi: \exp_stop_f:
        \msg_expandable_error:nn { char }
          { out-of-range }
      \else:
        \if_int_compare:w #2#1 = 100 \exp_stop_f:
          \msg_expandable_error:nn { char } { null-space }
        \else:
          \__char_generate_aux:nnw {#1} {#2}
        \fi:
      \fi:
    \fi:
    \exp_end:
  }

\begin{document}

\regex_match:nnTF
{ \x{3042}い }
{ あいうえお }
{ True }
{ False }

\end{document}