ときどきの雑記帖 RE* (新南口)
ロジカルアレルギーアワー
今週のしずえさん
「しおり」
日本シリーズ
オリックス vs ヤクルト @東京ドームになったら、 「元」阪急ブレーブスと「元」ヤクルトスワローズが後楽園球場(の後釜)で日本シリーズ …… ということで何かを期待せずにはいられない(笑)
employed
こんな使い方もあったのか。>employ
Software design patterns are like best practices employed by many experienced software developers. You can use design patterns to make your application scalable and flexible.
英語「employ」の意味・使い方・読み方 | Weblio英和辞書
タブレット
(たしか)7インチのAndroidタブレットや それより少し小さいKindle Paper Whiteを使っていると、 元が文庫本や新書サイズのものは問題ないのだけど 大きめの判型で固定フォーマットのものは 読むのがちょっと辛いので、 前回のタイムセールのときにKindle Fire(10インチ)を買ってみた。 7インチクラスに比べれば元が大きな本でもかなり読みやすいのだけど、 もう少し大きい方がいいかなあとは感じてたのね (そこ、老眼だろうとか言わない)。
なるほどこんな背景もあるのか。 でもiPad Proはちょっと(値段的に)無理かなあ。 PCもそろそろリプレースしたいし (が、昨今の半導体不足でどうなることやら。 メモリはケチりたくはないが財布の中身的に値段がいくらでも…とは)
雑誌を読むなら「iPad」一択? コストが気になるなら外部モニターという裏ワザも - 山口真弘のおすすめ読書タブレット比較 - 窓の杜
もちろんスマホなどに比べると圧倒的に大画面とはいえ、もともとがA4やB5に近いサイズの雑誌を見やすく表示するには、 10型クラスでは不十分であることは、認識しておく必要がある。
ちなみに同じ10型前後であれば、Androidタブレットでも候補がないわけではないが、 Androidの多くは画面の縦横比が16:10とワイドであるため、ページが幅に合わせて縮小されてしまい、 縦横比が4:3のiPadに比べると2周りほど小さくなる。そのぶん、前述のような制約がさらに厳しくなるので注意したい。
ふと、A4の斜めの長さって何インチなのか気になった (縦横はミリメートルでは覚えてるんだけど)。 そこで今回はbcで計算してみる。
kbk@toybox4:/mnt/c/Users/kbk$ bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
scale=5
sqrt(297^2+210^2)
363.74304
sqrt(297^2+210^2)/25.4
14.32059
ふむ。ほぼ14インチと。 じゃあ10インチのタブレットでも元がA4のものをみるのはそもそも結構きついってことか (縦横比は忘れる)。
M
まだこのネタ引っ張るのですよ😄
36DA5B7FEC924801
ところでふとN-BASIC時代の16進文字→2進4文字の変換テクニックとか思い出した。コードサイズを小さくするやつで。
— 29#色々作るひと (@MyCPU8) October 2, 2021
P=INSTR("36DA5B7FEC924801", H$) ;
B$=MID$("0011010111100100001", P, 4)
みたいなの。なつかしい。
このツイートにある文字列 36DA5B7FEC924801
がどこから出てきたのかわからない。
前回使った
def make_sequence(n1, n2)
seed = [0, 0, 1, 1]
result = Array.new(15+3)
seed.each_with_index do |e, i|
result[i] = e
end
4.upto(14+3) do |n|
result[n] = result[n-5+n1] ^ result[n-5+n2]
end
result
end
[1,2,3,4].combination(2) do |n1, n2|
seq = make_sequence(n1, n2)
hexs = seq.each_cons(4).collect{ _1.join.to_i(2).to_s(16) }
printf "[#{n1},#{n2}] %s %s %s\n", seq.join, hexs.join, hexs.sort.join
end
このスクリプトの「種」を上記のように3にして実行してみても
[1,2] 001101011110001001 36da5b7fec81249 123456789abcdef
[1,3] 001111001111001111 37fec937fec937f 33377799cceefff
[1,4] 001111010110010001 37feda5b6c92481 123456789abcdef
[2,3] 001110010111001011 37ec925b7ec925b 223557799bbccee
[2,4] 001110100111010011 37eda4937eda493 333447799aaddee
[3,4] 001101101101101101 36db6db6db6db6d 366666bbbbddddd
となってツイートにあるそれは出てこない。 もちろん総当たりで見つけた中から適当に採ったなどの可能性もあるんだろうけど 一見して特に面白みのある並びのようには見えないし…
というのはちょいと脇において、 「バイト&ワードの風にのって」に記載の手法 の出所(の出所)らしいのにたどり着いたので書いておく。
繰り返しのない列
さて、「バイト&ワードの風にのって」(中の「エレガントな解答もとむ」)では こういう手順で(0を含まない)パターンを生成していた。
まずはじめに、すべてが0ではない4ビットのパターン、たとえば0001を設定する。 そして、最初の2ビットのexclusive OR(排他的論理和)をとって、 その結果を第5ビットとする。次は第2ビット目と第3ビット目のexclusive OR を とって、第6ビットとする。以下、同様の操作を繰り返していく。
というものだったけど、以前リンクだけ貼っていた 補足 - 繰り返しのない列 を見るとこんな記述があって
【問題】 すべてのnビット列が1回ずつ登場する列(完全な列とよぶ)は存在するか? すべてのnビット列が1回ずつ登場する列とは、例えば次のように先頭からスライドしながら3ビットずつ抜き出すと 全ての3ビット列が1回ずつ登場する列のことである。
これでnが4だと今回の問題そのものになる。 そしてこの記事から階層を上って関連する記事を見ると
4. LFSR
* 予備知識としてのGF(2**n)
* LFSRはどこにXORを付けると周期が2**n-1になるのか
* 原始多項式の個数
* M系列はなぜ自己相関が高いのか
* M系列にはオールゼロ以外のすべてのnビット列が1回ずつ登場する
* CRCはどんなビット誤りを検出できるのか
* CRCの生成回路
* 補足 - 繰り返しのない列
といったものがあって、
LFSRはどこにXORをつけると周期2**n-1になるのか には
カウンタ値がオールゼロだとずっとオールゼロにとどまるので、使える値はオールゼロ以外の2^n-1個である。 実はXORをつける位置をうまく選ぶとカウンタ周期を最大の2^n-1にできるのだが、どこにXORをつければよいのだろうか。
という記述が、
M系列にはオールゼロ以外のすべてのnビット列が1回ずつ登場する には
M系列は周期2^3-1で0010111の繰り返しとなるが、このM系列の先頭からスライドしながら3ビットずつ抜き出すと 000以外の全ての3ビット列が1回ずつ登場する。
という記述があって、そこから新たなる(でもないか?)キーワード 「原始多項式」に遭遇した。
原始多項式
さて、その原始多項式についてまずはWikipediaから
次に,10番目と3番目のビットの排他的論理和を計算し,これを0番目のビットとする. そして,10番目のビットを出力するとともに、シードのビットを1つずつ左へずらす。 つまり、9番目のビットを10番目のビットに、8番目のビットを9番目のビットに、 と順にずらして0番目のビットを1番目とする.このプロセスを繰り返すことにより, 長さ 2^10 - 1 = 1023 のビット列を生成できる.
ここに書いてある手順も(当然ではあるが)同じと。
そしてn=4ビットの場合の原始多項式は
X4 + X + 1
とX4 + X3 + 1
の二つだけなので「最初の2ビット」(1ビット目と2ビット目)と 「1ビット目と4ビット目」を使った例が出ていたのですが、 4ビットから任意の2つのビットをとる組み合わせは6個あるから ほかのものはどうなるのだろうかと Rubyスクリプトを書いて確かめてみたところ…
[1,2] 000100110101111000 124936da5b7fec8 123456789abcdef
[1,3] 000101000101000101 125a48125a48125 1112224455588aa
[1,4] 000111101011001000 137feda5b6c9248 123456789abcdef
[2,3] 000101110010111001 125b7ec925b7ec9 122557799bbccee
[2,4] 000111010011101001 137eda4937eda49 133447799aaddee
[3,4] 000110110110110110 136db6db6db6db6 1366666bbbbdddd
こうなると。
0以外の並びを生成してからそこに0をくっつける(埋め込む)という 一点がちょっと引っかかるけど、まあこれが元ネタだろうなと。
参考
M系列関連ではこんな記事も。
M系列信号とは~生成法や定義を解説~ | 理系大学院生の知識の森
初期値の設定ができたら,i=1,j=5の値を求めます.
図に示したように,左から順番に排他的論理和を行います.
M-series generator polynomials
nビットのM系列の1周期の中の連続する n ビットはユニークである
- M系列の生成多項式と原始多項式について -生成多項式や原始多項式に関する様- | OKWAVE
- 原始多項式の個数
- M系列はなぜ自己相関が高いのか
- Maximum length sequence - Wikipedia
- 1と0★花鳥風月の風流を楽しんでる暇もない
- GF(2^n) 3次~16次の原始多項式を全部求めて一覧表にするプログラムpart5 - ずるやすみねこのリサイズ研究
数学いっちょんわからん… (使い方、これでいいすか?)
で
このネタまだ続けるのであった😄
rm
これも前回 の続き。
rm_fts
- coreutils/rm.c at master ・ coreutils/coreutils
- coreutils/remove.c at master ・ coreutils/coreutils
- gnulib/lib at master · coreutils/gnulib
- gnulib/fts.c at master · coreutils/gnulib
rm_fts を見ると
coreutils/remove.c at master · coreutils/coreutils
/* This function is called once for every file system object that fts
encounters. fts performs a depth-first traversal.
A directory is usually processed twice, first with fts_info == FTS_D,
and later, after all of its entries have been processed, with FTS_DP.
Return RM_ERROR upon error, RM_USER_DECLINED for a negative response
to an interactive prompt, and otherwise, RM_OK. */
static enum RM_status
rm_fts (FTS *fts, FTSENT *ent, struct rm_options const *x)
{
switch (ent->fts_info)
{
case FTS_D: /* preorder directory */
省略
/* Perform checks that can apply only for command-line arguments. */
if (ent->fts_level == FTS_ROOTLEVEL)
{
省略
/* POSIX also says:
If a command line argument resolves to "/" (and --preserve-root
is in effect -- default) diagnose and skip it. */
if (ROOT_DEV_INO_CHECK (x->root_dev_ino, ent->fts_statp))
{
ROOT_DEV_INO_WARN (ent->fts_path);
fts_skip_tree (fts, ent);
return RM_ERROR;
}
/* If a command line argument is a mount point and
--preserve-root=all is in effect, diagnose and skip it.
This doesn't handle "/", but that's handled above. */
if (x->preserve_all_root)
{
コメントから判断しておそらくこの辺がディレクトリ削除に関する部分で、 途中で呼び出している ROOT_DEV_INO_CHECK (おそらくマクロ)が怪しい。
そしてそれは実際、 coreutils/root-dev-ino.h at master · coreutils/coreutils で定義されているマクロ (上記のコードで(ROOT_DEV_INO_CHECKの少し後で使われている ROOT_DEV_INO_WARNもここ)。
ROOT_DEV_INO_CHECK
/* These macros are common to the programs that support the
--preserve-root and --no-preserve-root options. */
# define ROOT_DEV_INO_CHECK(Root_dev_ino, Dir_statbuf) \
(Root_dev_ino && SAME_INODE (*Dir_statbuf, *Root_dev_ino))
# define ROOT_DEV_INO_WARN(Dirname) \
do \
{ \
if (STREQ (Dirname, "/")) \
error (0, 0, _("it is dangerous to operate recursively on %s"), \
quoteaf (Dirname)); \
else \
error (0, 0, \
_("it is dangerous to operate recursively on %s (same as %s)"), \
quoteaf_n (0, Dirname), quoteaf_n (1, "/")); \
error (0, 0, _("use --no-preserve-root to override this failsafe")); \
} \
while (0)
ここでさらにSAME_INODE というのが出てきたので追いかける。 が、実はgithubにあるリポジトリにはこれが定義されているファイルはない。 というのも、これは何回かこれまでに見てきたような、 「本体」はgnulibにあって コンパイル時にはそこからコピーして使うというものだから。
SAME_INODE
どこでそれが見つけられるかというとこのへん。
最終的には Savannah Git Hosting - gnulib.git/blob - lib/same-inode.h になって、定義はこう。
/* Determine whether two stat buffers are known to refer to the same file.
さっくり略
# if defined __VMS && __CRTL_VER < 80200000
# define SAME_INODE(a, b) \
((a).st_ino[0] == (b).st_ino[0] \
&& (a).st_ino[1] == (b).st_ino[1] \
&& (a).st_ino[2] == (b).st_ino[2] \
&& (a).st_dev == (b).st_dev)
# elif defined _WIN32 && ! defined __CYGWIN__
/* Native Windows. */
# if _GL_WINDOWS_STAT_INODES
/* stat() and fstat() set st_dev and st_ino to 0 if information about
the inode is not available. */
# define SAME_INODE(a, b) \
(!((a).st_ino == 0 && (a).st_dev == 0) \
&& (a).st_ino == (b).st_ino && (a).st_dev == (b).st_dev)
# else
/* stat() and fstat() set st_ino to 0 always. */
# define SAME_INODE(a, b) 0
# endif
# else
# define SAME_INODE(a, b) \
((a).st_ino == (b).st_ino \
&& (a).st_dev == (b).st_dev)
# endif
話が前後するけど SAME_INODE がどういったもので何のためにあるのかは sys/stat.h (GNU Gnulib) に少し書かれている。
8.63 sys/stat.h
The macro S_IFBLK is missing on some platforms: MSVC 14.
On OpenVMS, st_ino is an array of three ino_t values, not a single value.
To partially work around the previous two problems, you can test for nonzero st_ino and use the Gnulib same-inode module to compare nonzero values. For example, SAME_INODE (a, b) is true if the struct stat values a and b are known to represent the same file, (a.st_ino && !SAME_INODE (a, b)) is true if they are known to represent different files, and !a.st_ino is true if it is not known whether they represent different files.
ということで、自前でパスの正規化などはしたりせず、 対象となっているのディレクトリのi-nodeを取得し、 それがデバイスのルートのものかどうかで判定している。 のだろう。たぶん。
inode of root directory
Linux のi-nodeとかパーティションとかファイルシステムとかマウントについて復習した - Qiita
ディレクトリの i-number はどうやって探す?
そのディレクトリの親ディレクトリが知っている。 ではその親ディレクトリの i-number はさらにその親が知っていて…と、 プロセスが親プロセスを辿るのと同じようにルートディレクトリの i-number って何?という話になる。 ルートディレクトリの i-number は歴史的経緯により 2 らしいです。
j*
シェルスクリプトで正規表現の照合シンボル[.string.]と等価クラス[=char=]と文字クラス[:classname:]を正しく使う方法 - Qiita
で
$ locale -k LC_CTYPE | grep ctype-class-names
ctype-class-names="upper";"lower";"alpha";"digit";"xdigit";"space";"print";
"graph";"blank";"cntrl";"punct";"alnum";"combining";"combining_level3";
"jspace";"jhira";"jkata";"jkanji";"jdigit"
というのが出てきたので、手元でもやってみた(Ubuntu 20.04)。
kbk@toybox4:/mnt/c/Users/kbk$ locale -k LC_CTYPE | grep ctype-class-names
ctype-class-names="upper";"lower";"alpha";"digit";"xdigit";"space";"print";
"graph";"blank";"cntrl";"punct";"alnum";"combining";"combining_level3"
おっと、localeが英語のままだった。
kbk@toybox4:/mnt/c/Users/kbk$ LC_CTYPE=ja_JP.UTF8 locale -k LC_CTYPE | grep ctype-class-names
ctype-class-names="upper";"lower";"alpha";"digit";"xdigit";"space";"print";
"graph";"blank";"cntrl";"punct";"alnum";"combining";"combining_level3";
"jspace";"jhira";"jkata";"jkanji";"jdigit"
kbk@toybox4:/mnt/c/Users/kbk$
ふむ。
/usr/share/i18n/locales/ja_JP にも書いてあるので [:jhira:] とか使えてもよさそうなんですが?
これ、プログラムから簡単に情報取れるのかな? /usr/share/i18n/locales/ja_JP がどんなものかと調べてみると
kbk@toybox4:/mnt/c/Users/kbk$ ls -l /usr/share/i18n/locales/ja_JP
-rw-r--r-- 1 root root 220701 Apr 15 2020 /usr/share/i18n/locales/ja_JP
kbk@toybox4:/mnt/c/Users/kbk$ file /usr/share/i18n/locales/ja_JP
/usr/share/i18n/locales/ja_JP: UTF-8 Unicode text
テキストファイルっぽい。
じゃあと実際に中身を見てみると…
comment_char %
escape_char /
% This file is part of the GNU C Library and contains locale data.
% The Free Software Foundation does not claim any copyright interest
% in the locale data contained in this file. The foregoing does not
% affect the license of the GNU C Library as a whole. It does not
% exempt you from the conditions of the license if your use would
% otherwise be governed by that license.
% Name: localedef for ja_JP
% Version: 0.7
% Date: 1999-12-05
% Write: HANATAKA, Shinya <hanataka@abyss.rim.or.jp>
で始まり
LC_IDENTIFICATION
title "Japanese language locale for Japan"
source "HANATAKA, Shinya, xxxxx@example.or.jp"
address ""
contact ""
email "xxxxxx@example.org"
tel ""
fax ""
language "Japanese"
territory "Japan"
revision "1.0"
date "2000-07-20"
category "i18n:2012";LC_IDENTIFICATION
category "i18n:2012";LC_CTYPE
category "i18n:2012";LC_COLLATE
category "i18n:2012";LC_TIME
category "i18n:2012";LC_NUMERIC
category "i18n:2012";LC_MONETARY
category "i18n:2012";LC_MESSAGES
category "i18n:2012";LC_PAPER
category "i18n:2012";LC_NAME
category "i18n:2012";LC_ADDRESS
category "i18n:2012";LC_TELEPHONE
category "i18n:2012";LC_MEASUREMENT
END LC_IDENTIFICATION
と続き (メールアドレスは改変しています)、
LC_CTYPE
% This is a copy of the "i18n" LC_CTYPE with the following modifications:
% - Additional classes: jspace jhira jkata jkanji jdigit
% - Additional maps: tojhira tojkata
copy "i18n"
charclass jspace;jhira;jkata;jkanji;jdigit
charconv tojhira;tojkata
jspace <U3000>
jdigit <UFF10>;<UFF11>;<UFF12>;<UFF13>;<UFF14>;/
<UFF15>;<UFF16>;<UFF17>;<UFF18>;<UFF19>
jhira <U3041>;<U3042>;<U3043>;<U3044>;<U3045>;<U3046>;<U3047>;<U3048>;/
<U3049>;<U304A>;<U304B>;<U304C>;<U304D>;<U304E>;<U304F>;<U3050>;/
<U3051>;<U3052>;<U3053>;<U3054>;<U3055>;<U3056>;<U3057>;<U3058>;/
<U3059>;<U305A>;<U305B>;<U305C>;<U305D>;<U305E>;<U305F>;<U3060>;/
<U3061>;<U3062>;<U3063>;<U3064>;<U3065>;<U3066>;<U3067>;<U3068>;/
<U3069>;<U306A>;<U306B>;<U306C>;<U306D>;<U306E>;<U306F>;<U3070>;/
<U3071>;<U3072>;<U3073>;<U3074>;<U3075>;<U3076>;<U3077>;<U3078>;/
<U3079>;<U307A>;<U307B>;<U307C>;<U307D>;<U307E>;<U307F>;<U3080>;/
<U3081>;<U3082>;<U3083>;<U3084>;<U3085>;<U3086>;<U3087>;<U3088>;/
<U3089>;<U308A>;<U308B>;<U308C>;<U308D>;<U308E>;<U308F>;<U3090>;/
<U3091>;<U3092>;<U3093>;<U309B>;<U309C>;<U309D>;<U309E>;<U30FC>
jkata <U30A1>;<U30A2>;<U30A3>;<U30A4>;<U30A5>;<U30A6>;<U30A7>;<U30A8>;/
<U30A9>;<U30AA>;<U30AB>;<U30AC>;<U30AD>;<U30AE>;<U30AF>;<U30B0>;/
<U30B1>;<U30B2>;<U30B3>;<U30B4>;<U30B5>;<U30B6>;<U30B7>;<U30B8>;/
<U30B9>;<U30BA>;<U30BB>;<U30BC>;<U30BD>;<U30BE>;<U30BF>;<U30C0>;/
<U30C1>;<U30C2>;<U30C3>;<U30C4>;<U30C5>;<U30C6>;<U30C7>;<U30C8>;/
<U30C9>;<U30CA>;<U30CB>;<U30CC>;<U30CD>;<U30CE>;<U30CF>;<U30D0>;/
<U30D1>;<U30D2>;<U30D3>;<U30D4>;<U30D5>;<U30D6>;<U30D7>;<U30D8>;/
<U30D9>;<U30DA>;<U30DB>;<U30DC>;<U30DD>;<U30DE>;<U30DF>;<U30E0>;/
<U30E1>;<U30E2>;<U30E3>;<U30E4>;<U30E5>;<U30E6>;<U30E7>;<U30E8>;/
<U30E9>;<U30EA>;<U30EB>;<U30EC>;<U30ED>;<U30EE>;<U30EF>;<U30F0>;/
<U30F1>;<U30F2>;<U30F3>;<U30F4>;<U30F5>;<U30F6>;<U309B>;<U309C>;/
<U30FD>;<U30FE>;<U30FC>;/
<UFF66>;<UFF67>;<UFF68>;<UFF69>;<UFF6A>;<UFF6B>;/
<UFF6C>;<UFF6D>;<UFF6E>;<UFF6F>;/
<UFF70>;/
<UFF71>;<UFF72>;<UFF73>;<UFF74>;<UFF75>;/
<UFF76>;<UFF77>;<UFF78>;<UFF79>;<UFF7A>;/
<UFF7B>;<UFF7C>;<UFF7D>;<UFF7E>;<UFF7F>;/
<UFF80>;<UFF81>;<UFF82>;<UFF83>;<UFF84>;/
<UFF85>;<UFF86>;<UFF87>;<UFF88>;<UFF89>;/
<UFF8A>;<UFF8B>;<UFF8C>;<UFF8D>;<UFF8E>;/
<UFF8F>;<UFF90>;<UFF91>;<UFF92>;<UFF93>;/
<UFF94>;<UFF95>;<UFF96>;/
<UFF97>;<UFF98>;<UFF99>;<UFF9A>;<UFF9B>;/
<UFF9C>;<UFF9D>;/
<UFF9E>;<UFF9F>
jkanji <U4E9C>;<U5516>;<U5A03>;<U963F>;<U54C0>;<U611B>;<U6328>;<U59F6>;/
<U9022>;<U8475>;<U831C>;<U7A50>;<U60AA>;<U63E1>;<U6E25>;<U65ED>;/
<U8466>;<U82A6>;<U9BF5>;<U6893>;<U5727>;<U65A1>;<U6271>;<U5B9B>;/
<U59D0>;<U867B>;<U98F4>;<U7D62>;<U7DBE>;<U9B8E>;<U6216>;<U7C9F>;/
省略
<U9F57>;<U9F58>;<U9F5A>;<U9F5D>;<U9F5E>;<U9F68>;<U9F69>;<U9F6D>;/
<U9F6E>;<U9F6F>;<U9F70>;<U9F71>;<U9F73>;<U9F75>;<U9F7A>;<U9F7D>;/
<U9F8F>;<U9F90>;<U9F91>;<U9F92>;<U9F94>;<U9F96>;<U9F97>;<U9F9E>;/
<U9FA1>;<U9FA2>;<U9FA3>;<U9FA5>;<U4EDD>;<U3005>;<U3007>
tojhira (<U30A1>,<U3041>);(<U30A2>,<U3042>);(<U30A3>,<U3043>);/
(<U30A4>,<U3044>);(<U30A5>,<U3045>);(<U30A6>,<U3046>);/
(<U30A7>,<U3047>);(<U30A8>,<U3048>);(<U30A9>,<U3049>);/
省略
(<U30E9>,<U3089>);(<U30EA>,<U308A>);(<U30EB>,<U308B>);/
(<U30EC>,<U308C>);(<U30ED>,<U308D>);(<U30EE>,<U308E>);/
(<U30EF>,<U308F>);(<U30F0>,<U3090>);(<U30F1>,<U3091>);/
(<U30F2>,<U3092>);(<U30F3>,<U3093>);/
(<U30FD>,<U309D>);(<U30FE>,<U309E>)
tojkata (<U3041>,<U30A1>);(<U3042>,<U30A2>);(<U3043>,<U30A3>);/
(<U3044>,<U30A4>);(<U3045>,<U30A5>);(<U3046>,<U30A6>);/
(<U3047>,<U30A7>);(<U3048>,<U30A8>);(<U3049>,<U30A9>);/
省略
(<U308C>,<U30EC>);(<U308D>,<U30ED>);(<U308E>,<U30EE>);/
(<U308F>,<U30EF>);(<U3090>,<U30F0>);(<U3091>,<U30F1>);/
(<U3092>,<U30F2>);(<U3093>,<U30F3>);/
(<U309D>,<U30FD>);(<U309E>,<U30FE>)
translit_start
include "translit_combining";""
include "translit_cjk_variants";""
translit_end
END LC_CTYPE
とこの辺りが関連している内容のようだけど (ファイルはこの後も他のエントリが続きますが今回の話には関係ないので略)、 確かにこういった情報があれば対応は可能ではあるけれども このような「テキスト」で定義を書かれてもプログラムから扱うのは大変ですよねー。
ふと思い出したけどこういう「定義の形式」は はるか昔(前世紀)に
辺りで見た覚えが(多分IIIの技術編)。
ところでja_JP先頭にある日付からして時期的に仕方がないのかもしれないけど、 jhira、jkata、jkanjiといった名前はあまり好ましいものではないんじゃないかなあ。 いい代替案があるわけではないけど。
glibc regex
さて、現状のglibcの(というかGNULib Regular expressions (GNU Gnulib)の) regexでこの文字クラスの扱いがどうなっているかというとですね
gnulib/regcomp.c at master · coreutils/gnulib
/* Helper function for parse_bracket_exp.
Build the character class which is represented by NAME.
The result are written to MBCSET and SBCSET.
CHAR_CLASS_ALLOC is the allocated size of mbcset->char_classes,
is a pointer argument since we may update it. */
static reg_errcode_t
#ifdef RE_ENABLE_I18N
build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
re_charset_t *mbcset, Idx *char_class_alloc,
const char *class_name, reg_syntax_t syntax)
#else /* not RE_ENABLE_I18N */
build_charclass (RE_TRANSLATE_TYPE trans, bitset_t sbcset,
const char *class_name, reg_syntax_t syntax)
#endif /* not RE_ENABLE_I18N */
{
int i;
const char *name = class_name;
/* In case of REG_ICASE "upper" and "lower" match the both of
upper and lower cases. */
if ((syntax & RE_ICASE)
&& (strcmp (name, "upper") == 0 || strcmp (name, "lower") == 0))
name = "alpha";
#ifdef RE_ENABLE_I18N
/* Check the space of the arrays. */
if (__glibc_unlikely (*char_class_alloc == mbcset->nchar_classes))
{
/* Not enough, realloc it. */
/* +1 in case of mbcset->nchar_classes is 0. */
Idx new_char_class_alloc = 2 * mbcset->nchar_classes + 1;
/* Use realloc since array is NULL if *alloc == 0. */
wctype_t *new_char_classes = re_realloc (mbcset->char_classes, wctype_t,
new_char_class_alloc);
if (__glibc_unlikely (new_char_classes == NULL))
return REG_ESPACE;
mbcset->char_classes = new_char_classes;
*char_class_alloc = new_char_class_alloc;
}
mbcset->char_classes[mbcset->nchar_classes++] = __wctype (name);
#endif /* RE_ENABLE_I18N */
#define BUILD_CHARCLASS_LOOP(ctype_func) \
do { \
if (__glibc_unlikely (trans != NULL)) \
{ \
for (i = 0; i < SBC_MAX; ++i) \
if (ctype_func (i)) \
bitset_set (sbcset, trans[i]); \
} \
else \
{ \
for (i = 0; i < SBC_MAX; ++i) \
if (ctype_func (i)) \
bitset_set (sbcset, i); \
} \
} while (0)
if (strcmp (name, "alnum") == 0)
BUILD_CHARCLASS_LOOP (isalnum);
else if (strcmp (name, "cntrl") == 0)
BUILD_CHARCLASS_LOOP (iscntrl);
else if (strcmp (name, "lower") == 0)
BUILD_CHARCLASS_LOOP (islower);
else if (strcmp (name, "space") == 0)
BUILD_CHARCLASS_LOOP (isspace);
else if (strcmp (name, "alpha") == 0)
BUILD_CHARCLASS_LOOP (isalpha);
else if (strcmp (name, "digit") == 0)
BUILD_CHARCLASS_LOOP (isdigit);
else if (strcmp (name, "print") == 0)
BUILD_CHARCLASS_LOOP (isprint);
else if (strcmp (name, "upper") == 0)
BUILD_CHARCLASS_LOOP (isupper);
else if (strcmp (name, "blank") == 0)
BUILD_CHARCLASS_LOOP (isblank);
else if (strcmp (name, "graph") == 0)
BUILD_CHARCLASS_LOOP (isgraph);
else if (strcmp (name, "punct") == 0)
BUILD_CHARCLASS_LOOP (ispunct);
else if (strcmp (name, "xdigit") == 0)
BUILD_CHARCLASS_LOOP (isxdigit);
else
return REG_ECTYPE;
return REG_NOERROR;
}
とこんなんですよ。
これらの集合にはそれぞれ対応する「isなんちゃら」という関数があるから話は簡単ですが、 「jかんたら」というのを(locale次第で)追加するにはどうしたらいいんでしょうかね? (という読者(謎)への宿題)
追記
iswctype とかすっかり忘れていた(笑) wcなんちゃらな関数は書く前に(どんなものがあったのか)調べなおしたんだけど 目が節穴だった模様。
zsh
I don’t know why bash is the de-facto default,
zshのグロビング部分のコード読みも途中だなあ。