初歩のシェルスクリプトで遊ぶ[ぬかみそフォントの制作サポート(9)]
VSつきの文字を抜き出す
$ cat ivstest.txt
ななかまど
辻󠄀
辻󠄀辻味噌󠄀味噌
$ cat ivstest.txt |./ttedit_20210327_02.sh --html
ななかまど
辻󠄀
辻󠄀辻味噌󠄀味噌
という感じに、異体字セレクタつきのテキストデータを入れると、異体字セレクタだけをHTMLの数値参照に変換したり、異体字セレクタつきの文字だけ抜き出したり、異体字セレクタつきの文字だけ反転表示したり、とできます。
不満の残るスクリプトだけれど、とりあえず無いよりはマシです。
TTEdit/OTEditがデフォルトで作るフォントは、今まで異体字セレクタは使えなかったはず、なんだけれども。OTEditの新しい、文字数の多いやつだと、IVSが使えるみたい。そのへんを扱うための、道具作りです。
#!/bin/bash #!/usr/bin/zsh # ======================================================================================= # ■ VSつきテキスト文字とVSなし文字を分離,VSを可視化,VSをHTML数値参照へ変換_[bash版] # # ▼ 異体字セレクタ (U+E0100〜U+E01EF, VS17~VS256) 検出 # # iconvとodで16進数に変換表示して、「00 0e 01 00」〜「00 0e 01 ef」を探す方式 # # # ・1文字1行4バイト、 # ・VSは文字の直後に付加して1文字1行8バイト # # 00 00 30 4b # 00 00 30 7e # 00 00 30 69 # 00 00 00 0d # 00 00 00 0a # 00 00 8f bb 00 0e 01 00 # 00 00 00 0d # 00 00 00 0a # # # 4バイトの行だけ抜き出せば、VSなしの文字のみ抜き出せる。 # 8バイトの行のみ抜き出せば、VSつきの文字のみ抜き出せる。 # 8バイトの行の後半4バイトに「&#x ;」を付加すると、数値参照に変換できる。 # 8バイトの行の前後にエスケープシーケンスを付加すると、色反転表示ができる。 # # # ▼ 入力 # stdinにテキストデータ # # ▼ 出力 # stdout # # # ▼ 必要なコマンド # iconv # od # # ======================================================================================= #exitParm='0' outputType='view' case "${1}" in ( --base ) # VSが無い文字のみ抜き出す outputType='base' ;; ( --vs ) # VSがついている文字のみ抜き出す outputType='vs' ;; ( --html ) # VSをhtmlの数値参照に書き換える outputType='html' ;; ( * ) # VSつきの文字を反転表示 outputType='view' ;; esac iconv -f utf8 -t utf32be | od -tx1 -An -v -w4 | { while read Byte3 Byte2 Byte1 Byte0 ; do printf -v Byte0dec '%d' "0x${Byte0}" if test "${Byte3}${Byte2}${Byte1}" = '000e01' && test ${Byte0dec} -ge 0 && test ${Byte0dec} -le 239 ; then printf ' %s %s %s %s\n' ${Byte3} ${Byte2} ${Byte1} ${Byte0} else printf '\n %s %s %s %s' ${Byte3} ${Byte2} ${Byte1} ${Byte0} fi done echo } | sed -e '/^$/d' | { case "${outputType}" in # ---------------------------------------------- ( base ) # ---------------------------------------------- sed -n -e ' /^ .. .. .. ..$/{ p }' | while read B3 B2 B1 B0 ; do printf "\U${B3}${B2}${B1}${B0}" done ;; # ---------------------------------------------- ( vs ) # ---------------------------------------------- sed -n -e ' /^ .. .. .. .. 00 0e 01 ..$/{ p }' | while read B7 B6 B5 B4 B3 B2 B1 B0 ; do printf "\U${B7}${B6}${B5}${B4}\U${B3}${B2}${B1}${B0}" done ;; # ---------------------------------------------- ( html ) # ---------------------------------------------- while read B7 B6 B5 B4 B3 B2 B1 B0 ; do if test "${B3}${B2}${B1}" = '000e01' ; then printf "\U${B7}${B6}${B5}${B4}" printf '&#x%s;' "e01${B0}" else printf "\U${B7}${B6}${B5}${B4}" fi done ;; # ---------------------------------------------- ( view ) # ---------------------------------------------- # 1行8バイトの行のみ、前後に文字反転エスケープシーケンスを # \uで叩き込む # \033[7m 1b 5b 37 6d # \033[0m 1b 5b 30 6d while read B7 B6 B5 B4 B3 B2 B1 B0 ; do case "${B3}" in ( '' ) printf "\U${B7}${B6}${B5}${B4}" ;; ( * ) printf '\u1b\u5b\u37\u6d' printf "\U${B7}${B6}${B5}${B4}\U${B3}${B2}${B1}${B0}" printf '\u1b\u5b\u30\u6d' ;; esac done esac }
#!/bin/sh #!/usr/bin/yash #!/usr/bin/ksh #!/bin/bash # ======================================================================================= # ■ VSつきテキスト文字とVSなし文字を分離,VSを可視化,VSをHTML数値参照へ変換[xxd不要版] # # ▼ 異体字セレクタ (U+E0100〜U+E01EF, VS17~VS256) 検出 # iconvでutf32beに変換し、odでダンプリスト表示して、 # 「00 0e 01 00」〜「00 0e 01 ef」を探す方式、の一種。 # # ・「xxd -r -p」を使わずに済ませるため、odコマンドでは8進数に変換する。 # 8進数ならprintfでバイナリを作成できるため。 # # # ・1文字1行4バイト、 # ・VSは文字の直後に付加して1文字1行8バイト # # 00 00 30 4b # 00 00 30 7e # 00 00 30 69 # 00 00 00 0d # 00 00 00 0a # 00 00 8f bb 00 0e 01 00 # 00 00 00 0d # 00 00 00 0a # # # 4バイトの行だけ抜き出せば、VSなしの文字のみ抜き出せる。 # 8バイトの行のみ抜き出せば、VSつきの文字のみ抜き出せる。 # 8バイトの行の後半4バイトに「&#x ;」を付加すると、数値参照に変換できる。 # 8バイトの行の前後にエスケープシーケンスを付加すると、色反転表示ができる。 # # # ▼ 入力 # stdinにテキストデータ # # ▼ 出力 # stdout # # # ▼ 必要なコマンド # iconv # od # # ======================================================================================= #exitParm='0' outputType='view' # 動作切り替え指定 case "${1}" in ( --base ) # VSが無い文字のみ抜き出す outputType='base' ;; ( --vs ) # VSがついている文字のみ抜き出す outputType='vs' ;; ( --html ) # VSをhtmlの数値参照に書き換える outputType='html' ;; ( * ) # VSつきの文字を反転表示 outputType='view' ;; esac xxdFakeSh(){ ( # 入力は 3桁の8進数 複数バイト入力可能 IFS_BAK="${IFS}" while read octalByteLine ; do set -- ${octalByteLine} IFS='\' printf '\'"${*}" IFS="${IFS_BAK}" done ) } out2hex2utf32beFunc(){ # 8進数を16進数に変換し、 # 16進数を「10」の位の数字と「01」の位の数字に分け、 # utf32beの8進数ダンプリスト形式で出力する。 Hex0=`printf '%02x' "0${1}"` utf32_0='\060' ; utf32_1='\061' utf32_2='\062' ; utf32_3='\063' utf32_4='\064' ; utf32_5='\065' utf32_6='\066' ; utf32_7='\067' utf32_8='\070' ; utf32_9='\071' utf32_a='\141' ; utf32_b='\142' utf32_c='\143' ; utf32_d='\144' utf32_e='\145' ; utf32_f='\146' Hex0_10=${Hex0%?} # 16進数10の位の文字 Hex0_01=${Hex0#?} # 16進数01の位の文字 eval 'printf "\000\000\000${utf32_'${Hex0_10}'}\000\000\000${utf32_'${Hex0_01}'}"' # (補注)サブシェル動作も可能 } # 1.入力テキストをutf32beに変換 # 2.バイナリ8進数表記、1行4バイト(一文字)に並び替え # 3.4バイトずつデータを調査して、VSではないならば、改行してから改行なし出力 # 「(改行) # 入力4バイト16進数値をそのまま出力(改行なし)」 # 4.VSならば、そのまま出力して改行 # 5.空行を削除 iconv -f utf8 -t utf32be | od -to1 -An -v -w4 | { while read Byte3 Byte2 Byte1 Byte0 ; do if test "${Byte3}${Byte2}${Byte1}" = '000016001' && test ${Byte0} -ge 0 && test ${Byte0} -le 357 ; then printf ' %s %s %s %s\n' ${Byte3} ${Byte2} ${Byte1} ${Byte0} else printf '\n %s %s %s %s' ${Byte3} ${Byte2} ${Byte1} ${Byte0} fi done echo } | sed -e '/^$/d' | { # ^ 00 00 72 59 00 0e 01 00$ # ^ 00 00 30 7f$ # # データを整形しておく。odコマンドの出力に合わせる。 # 「半角空白-8進数1バイト」の繰り返しにすること。 # 行頭に半角空白が必須。 case "${outputType}" in # ---------------------------------------------- ( base ) # ---------------------------------------------- sed -n -e ' /^ ... ... ... ...$/{ p }' | xxdFakeSh | iconv -f utf32be -t utf8 ;; # ---------------------------------------------- ( vs ) # ---------------------------------------------- sed -n -e ' /^ ... ... ... ... 000 016 001 ...$/{ p }' | xxdFakeSh | iconv -f utf32be -t utf8 ;; # ---------------------------------------------- ( html ) # ---------------------------------------------- # &#x 000 000 000 046 000 000 000 043 000 000 000 170 # e01 000 000 000 145 000 000 000 060 000 000 000 061 # ; 000 000 000 073 while read B7 B6 B5 B4 B3 B2 B1 B0 ; do if test "${B3}${B2}${B1}" = '000016001' ; then # 基底文字を出力 printf '\'${B7}'\'${B6}'\'${B5}'\'${B4} # HTML数値参照を出力 # 外部コマンドを使わない実装 printf '\000\000\000\046\000\000\000\043\000\000\000\170' # &#x printf '\000\000\000\145\000\000\000\060\000\000\000\061' # e01 out2hex2utf32beFunc ${B0} printf '\000\000\000\073' # ; # HTML数値参照を出力 # 外部コマンドを使う実装 #B0hex=`printf '%02x' "0${B0}"` #printf '&#x%s;' "e01${B0hex}" | iconv -f utf8 -t utf32be else printf '\'${B7}'\'${B6}'\'${B5}'\'${B4} fi done | iconv -f utf32be -t utf8 ;; # ---------------------------------------------- ( view ) # ---------------------------------------------- # 1行8バイトの行のみ、前後に文字反転エスケープシーケンスを # バイナリ表記で叩き込む # \033[7m 000 000 000 033 000 000 000 133 000 000 000 067 000 000 000 155 # \033[0m 000 000 000 033 000 000 000 133 000 000 000 060 000 000 000 155 sed -n -e ' /^ ... ... ... ... ... ... ... ...$/{ i\ 000 000 000 033 000 000 000 133 000 000 000 067 000 000 000 155 p i\ 000 000 000 033 000 000 000 133 000 000 000 060 000 000 000 155 d } p ' | xxdFakeSh | iconv -f utf32be -t utf8 ;; esac }
終了コードを設定したいのだけれど、どうやったら簡単にできるのか、いいのが思いつかん。パイプは難しい。
異体字セレクタがあれば0、無ければ1、とかにしたいんだが。異体字セレクタ文字を抜き出して出力が無ければ1だ、っつうのは、どうもなぁ。