第32回シェル芸勉強会 Q5 の解答

前置き

今日も今日とて第32回シェル芸勉強会の問題を解いていきます。
今日はQ5です。

第32回シェル芸勉強会の問題は次のURLにあります。
【問題のみ】jus共催 第32回全くインスタ映えしないシェル芸勉強会 | 上田ブログ

思考を忠実にアウトプットすることを目標にしています。

Q5 問題(上記URLからコピー)

ウムラウトを含む単語だけ抽出してください。ワンライナー中にウムラウトを使用しないでください。

wäschst wash 山田x Schrödinger
y上田 Ö アイウエオ unko
Übel Ärztin hoge カキクケコ

問題を見た感想・補足

マルチバイト文字が来たらとりあえずバイナリが見たくなる。

入力はGitHubリポジトリにあった umlaut.txtを使います。

解答1(邪道)

cat umlaut.txt | tr \  \\n | LANG=C grep -v '^[a-z山田上アイウエオカキクケコ]*$'

解説

感想で言っていることはさておき、「ワンライナー中にウムラウトを使用しないでください」ということはウムラウト以外ならいいはずです。

ウムラウトを含む列を引っ張ってくるなら grep '[ウムラウトたち]' をすればいいですが、grep -v '^[ウムラウト以外]*$' が等価になります。
ただ、私の環境ではä[a-z]指定で何故か引っかかってくるのでLANG=Cを指定しています。([a-z]は引っかかってaは引っかからないのに、[b-z]も引っかからない謎。)
f:id:nogiro_iota:20171210004613p:plain

それで、最終出力は行ではなく単語なので、tr ' ' '\n'で空白を改行コードに先に置き換えておいてやると、求めている結果になります。
まー結局ウムラウト書いてるのと変わらないのでこの解答ではダメでしょう。

解答2

cat umlaut.txt | grep -o . | sed 's#.#echo & | xxd -ps#' | sh | awk 'length==6' | xxd -r -p | grep -f - <(tr ' ' '\n' < umlaut.txt)

解説

ウムラウトを扱うコマンド系のことは何もわからないので、とりあえず汎用的なフォーマットであるバイナリから攻めて行くしか私には方法がありません。(ググれと言ってはいけない

ウムラウトのバイナリ値と、入力ファイルのバイナリ値を見ていきます。
(長いのでたたんでいます。 はてなブログでソースコードを折りたたむ方法 - おもちゃラボ

上記2つの結果を眺めると、ウムラウトは2バイト文字で、さらに元ファイルに含まれる2バイト文字はすべてウムラウトであることがわかります。

そのため、元ファイル中に含まれる2バイト文字でgrepすると答えが得られます。

まとめ

バイナリを眺めてみるとパターンがあったので、それを利用しました。

感想

ファイルのデータに依存してるのが個人的には気に入らない解答ですが、ウムラウトを扱う方法がわからないので。。。
他に2バイト文字が当ったらどうすれば良かったんだろう。