平衡点
2014/10/07
_ マルチバイト文字列の幅を 2 としてカウントする
ログインシェルは zsh ですが, あまりカスタマイズしていない佐々木ですこんばんは. 業務で Windows で作成されたらしき日本語の暗号化 zip ファイルを受け取ってじたばたすることが, 最近になって(ようやく?)無視できないくらい増えてきて嫌気がさしています. 外部にファイルを添付して送信する場合に暗号化した zip ファイルにして送信するって文化は誰が勧めたんでしょうね. 心底無駄なんでやめて欲しいです.
本題
zsh の RPROMT で今いるディレクトリを表示させています. 右端に表示させたいので
# source: sh # 変数の文字列計算用関数 function count_prompt_chars (){ print -n -P -- "$1" | sed -e $'s/\e\[[0-9;]*m//g' | wc -m | sed -e 's/ //g' } # precmd のプロンプト更新用関数 function update_prompt (){ ## プロンプト: 1段目左 local ps_user="%(!,%B%F{magenta}%n%b,%n)" local ps_host="%m" [[ -n ${SSH_CONNECTION} ]] && ps_host="%F{yellow}%m%f" local prompt_1st_left="[$ps_user@$ps_host$chroot_info]" ## プロンプト: 1段目右 local prompt_1st_right="[%F{white}%(5~,%-2~/.../%1~,%~)%f]" ## 1段目行の残り文字列の計算 local left_length=$(count_prompt_chars $prompt_1st_left) local right_length=$(count_prompt_chars $prompt_1st_right) local bar_rest_length=$[ COLUMNS - left_length - right_length -1 ] ## 1段目に水平線を引く local prompt_1st_hr=${(l:${bar_rest_length}::-:)} ## PROMPT の設定 # @see Zshをかわいくする.zshrcの設定 # URL: http://qiita.com/kubosho_/items/c200680c26e509a4f41c # 横幅等を調整. local ps_status="[%j]%(?.%B%F{green}.%B%F{blue})%(?!(*'-')%b!(*;-;%)%b)%f " local ps_mark="%(!,%B%F{magenta}#%f%b,%%)" PROMPT="$prompt_1st_left$prompt_1st_hr$prompt_1st_right-"$'\n'"$ps_status$ps_mark " PROMPT2='|%j]> ' SPROMPT="[%j]%B%F{red}%{$suggest%}(*'~'%)?<%b %U%r%u is correct? [n,y,a,e]:%f " # 右プロンプト RPROMPT="$ps_vcs_info" } precmd_functions+=update_prompt
なんて.
ですが, zip を展開して日本語のディレクトリなんかができてしまうと...
原因は wc -c なのですが, これを例えば wc -m なんてすると, 文字数のカウントは正しくなりますが, 表示自体はズレます. なので, ASCII では 1, それ以外では 2 を返すようにしたくなりました.
sed なんかでじたばたしていた訳ですが...
wc -m で文字数カウントできるのはありがたいが、マルチバイトの時には2、それ以外は1を返すようにできないだろうか…
— Youhei SASAKI (@uwabami) 2014, 10月 7
@uwabami sedは拡張正規表現ではないので ? はエスケープ不要だった。
sed 's/?/./g' input.txt |iconv -f UTF-8 -t US-ASCII//TRANSLIT |sed 's/?/../g' |wc -m
— シェルまおう(電子書籍セール沼出身) (@satoh_fumiyasu) 2014, 10月 7
@uwabami sed 's/[^\x01-\x7e]/../g' input.txt |wc -m で充分そうな気もしました。ご参考まで。
— シェルまおう(電子書籍セール沼出身) (@satoh_fumiyasu) 2014, 10月 7
なるほど. 勉強になります.
というわけで
# source: sh function count_prompt_chars (){ # @see https://twitter.com/satoh_fumiyasu/status/519386124020482049 print -n -P -- "$1" | sed -e $'s/\e\[[0-9;]*m//g' | sed -e 's/[^\x01-\x7e]/aa/g' | wc -m | sed -e 's/ //g' }
としてみました. これで幸せ.
という現実逃避ネタでした.
(追記) 早速ツッコミ頂きました.
@uwabami おつです。好みの問題ですが、sed は
sed -e $'s/\e\[[0-9;]*m//g' -e 's/[^\x01-\x7e]/aa/g'
のように一回でよさげ。
— シェルまおう(電子書籍セール沼出身) (@satoh_fumiyasu) 2014, 10月 7
おっしゃる通りです..._| ̄|○