参加しました
今回は声を出す参加者を募集してYouTubeで配信というスタイルだったようです。会場のうめき声を思い出させるような感じになるかと思いましたが、最後の方は無言になってましたね…そういえば会場の時もうめき声というよりは無言だったような…
さて今回も最中に解けたものに関して解答を残しておきます。先にネタバレをしておきますが、今回は最後の数問が激ムズでした。
Q1
big_dipper
ファイルにはAAで北斗七星が書いてあります。
$ cat big_dipper * * * * * * *
ほんとだ・・・。さてこれの*
に「チキチキボーン」を順番に当てはめてくださいという問題。早速やってみます。
$ cat ./Sh*/v*52/chiki | grep -o . | xargs -I@ echo '0,/\*/ s/\*/@/' | sed -f- ./Sh*/v*52/b* チ キ チ キ ボ ー ン
これがかの有名なチキチキボーン七星か。さて解答についてですが、まずはxargs
でsed
の命令を生成していきます。
$ cat ./Sh*/v*52/chiki | grep -o . | xargs -I@ echo '0,/\*/ s/\*/@/' 0,/\*/ s/\*/チ/ 0,/\*/ s/\*/キ/ 0,/\*/ s/\*/チ/ 0,/\*/ s/\*/キ/ 0,/\*/ s/\*/ボ/ 0,/\*/ s/\*/ー/ 0,/\*/ s/\*/ン/
最初にマッチした*
だけを置換してほしいので、0,/\*/
で置換範囲を制限しています。あとはこれをsed
に与えればよいですね。
PowerShellでの解答。こちらもsedを使うのが楽なので、sedを使います。ということで、上の命令を生成するところまでやってみましょう
$ (cat .\chiki -Encoding UTF8) -split '' | ?{$_} | %{"0,/\*/ s/\*/$_/"} 0,/\*/ s/\*/チ/ 0,/\*/ s/\*/キ/ 0,/\*/ s/\*/チ/ 0,/\*/ s/\*/キ/ 0,/\*/ s/\*/ボ/ 0,/\*/ s/\*/ー/ 0,/\*/ s/\*/ン/
特に難しそうなところはないですね。あえて取り上げるとしたら、?{$_}
で空行を削除しているところですかね。
ところでチキチキボーンって何?
Q2
チキチキボーンを連続して出力してください。ただし文字は^の上かvの下に出力してください。^
とv
はupdown
というファイルに記述されています。という問題
$ cat Sh*/vol.52/updown | grep -o . | paste - <(yes $(cat Sh*/vol.52/chiki)|head -n3|grep -o .|head -n20) | awk '$1 == "^"{print $2" ^ "}$1 == "v"{print " v "$2}' | rs -t | sed 's/ //g' チ チキボー チキチキボ キ ^ v ^ ^ ^ ^ v ^ ^ ^ ^ ^ v v v v v ^ v v キ ン ーンチキチ ボー
横に展開するデータをシェル芸で作るのは難しいので、まずは縦で作ってから転地するという方法。たまにありますよね。
$ cat Sh*/vol.52/updown | grep -o . | paste - <(yes $(cat Sh*/vol.52/chiki)|head -n3|grep -o .|head -n20) ^ チ v キ ^ チ ^ キ ^ ボ ^ ー v ン ^ チ ^ キ ^ チ ^ キ ^ ボ v ー v ン v チ v キ v チ ^ キ v ボ v ー
まずはこんなのを作っておきます。そしてawk
なりで、^
なら左に、v
なら右にチキチキボーンを並べてきます。成形のため、反対側には全角スペースを置いておくといいと思います
$ cat Sh*/vol.52/updown | grep -o . | paste - <(yes $(cat Sh*/vol.52/chiki)|head -n3|grep -o .|head -n20) | awk '$1 = = "^"{print $2" ^ "}$1 == "v"{print " v "$2}' チ ^ v キ チ ^ キ ^ ボ ^ ー ^ v ン チ ^ キ ^ チ ^ キ ^ ボ ^ v ー v ン v チ v キ v チ キ ^ v ボ v ー
なんかそれっぽくなりましたね。これの縦と横を入れ替えれば目的の形になりそうですが、これにはtateyoko
やrs -T
を私はよく使います
$ cat Sh*/vol.52/updown | grep -o . | paste - <(yes $(cat Sh*/vol.52/chiki)|head -n3|grep -o .|head -n20) | awk '$1 = = "^"{print $2" ^ "}$1 == "v"{print " v "$2}' | rs -T | sed 's/ //g' チ チキボー チキチキボ キ ^ v ^ ^ ^ ^ v ^ ^ ^ ^ ^ v v v v v ^ v v キ ン ーンチキチ ボー
最後のsed
は成形用ですね。
今度はPowerShellでの解答です。
$ (cat .\updown) -split '' | ?{$_} |% -Begin { $a=$b=$i=0; $c=@("","",""); $chiki=(cat -Encoding UTF8 ./chiki) } { $d=[int]($_ -eq "^"); $c[0]+=@(" ", $chiki[$i%7])[$d]; $c[1]+="$_ "; $c[2]+=@($chiki[$i++%7], " ")[$d] } -End { $c } チ チキボー チキチキボ キ ^ v ^ ^ ^ ^ v ^ ^ ^ ^ ^ v v v v v ^ v v キ ン ーンチキチ ボー
そう…ですね…Foreach-Object
のごり押し…awk
ごり押しみたいなもんです。
Q3
出来るをできるにして、side-by-sideでdiffを表示する問題
自分はdiff
の代わりにdelta
をよく使うのでそれでやりました。diff -yでも同じことができるとのこと。
$ delta -s <(sed 's/出来/でき/g' Sh*/vol.52/dekiru) ./Sh*/vol.52/dekiru
Q4
aho.html
から間違ってるタグを見つけてください
一発で見つける必要はなくて、使われているタグを集計して、目grepで間違いを探すというのがよさそうです。
$ cat Sh*/v*52/aho.html | grep -oPe "<[^ >]+>|</[^>]+>" | sort | uniq -c | sort -rn 269 </a> 258 </span> 54 </div> 31 </p> 29 <p> 25 </li> 23 <li> 18 </code> 17 </script> 16 </pre> 12 </ul> 11 <ul> 12 </ul> 11 <ul> 10 </i> 9 </h2> 8 <code> 7 </h4> 7 </h3> 6 <pre> 6 </aside> 5 <script> 3 <span> 3 </button> 2 <aside> 2 </ins> 2 </h5> 2 </h1> 1 <title> 1 <hr> 1 <head> 1 <h1> 1 <footer> 1 <body> 1 </title> 1 </strong> 1 </spin> 1 </nav> 1 </html> 1 </head> 1 </form> 1 </footer> 1 </body>
</spin>
があるのでこれがおかしいですね。あとは場所を特定するだけです
$ cat Sh*/v*52/aho.html | grep --color=auto -n spin 293:<a class="sourceLine" id="cb10-2" title="2"><span class="fu">awk</spin> <span class="st">'{t=2*3.14*$2/1000000000;c=cos(t)*5+5;s=sin(t)*10+13;</span></a>}
293行目とのことでした。
さて次はPowerShellですね。集計は以下のようにしてやります
$ cat .\aho.html | sls "<[^ >]+>|</[^>]+>" | %{$_.Matches.Value} | group | sort Count -Descending Count Name Group ----- ---- ----- 152 </span> {</span>, </span>, </span>, </span>...} 69 </a> {</a>, </a>, </a>, </a>...} 29 <p> {<p>, <p>, <p>, <p>...} 24 </div> {</div>, </div>, </div>, </div>...} 23 <li> {<li>, <li>, <li>, <li>...} 14 </script> {</script>, </script>, </script>, </script>...} 12 </ul> {</ul>, </ul>, </ul>, </ul>...} 10 </i> {</i>, </i>, </i>, </i>...} 8 </h2> {</h2>, </h2>, </h2>, </h2>...} 7 </h3> {</h3>, </h3>, </h3>, </h3>...} 6 </aside> {</aside>, </aside>, </aside>, </aside>...} 6 <pre> {<pre>, <pre>, <pre>, <pre>...} 6 <ul> {<ul>, <ul>, <ul>, <ul>...} 4 <script> {<script>, <script>, <script>, <script>} 4 </code> {</code>, </code>, </code>, </code>} 3 </button> {</button>, </button>, </button>} 2 </ins> {</ins>, </ins>} 2 </p> {</p>, </p>} 2 <aside> {<aside>, <aside>} 2 </li> {</li>, </li>} 1 </body> {</body>} 1 </html> {</html>} 1 <footer> {<footer>} 1 </spin> {</spin>} 1 <hr> {<hr>} 1 </footer> {</footer>} 1 <body> {<body>} 1 </form> {</form>} 1 <title> {<title>} 1 </head> {</head>} 1 </nav> {</nav>} 1 </h1> {</h1>} 1 </strong> {</strong>} 1 <h1> {<h1>} 1 <head> {<head>}
grep -o
に相当するのが sls "pattern" | %{$_.Matches.Value}
です。普段使いしていないので、すぐ忘れてしまう。
Q5
annotation.md
には脚注があります。これをTeX形式の\footnote{...}
にしながら元の場所に埋め込んで下さいという問題。
激しそうだけど、sedの命令を作り上げるのが良さそうということで、早速やってみます
$ cat Sh*/v*52/annotation.md | tail -n4 | rargs -p "\[\^(.+)\]: (.+)" echo "s/([^^])\[\^{1}\]/\1\\\footnote{{2}}/" | sed -E -f- ./Sh*/v*52/annotation.md # Aについて A\footnote{Aの起源は室町時代に遡る。}は素晴らしい。 Aのに似たものとしてB[^about_b]が存在するが、やはりAには及ばない。 他方でAに匹敵すると言われるC\footnote{Cの起源は江戸時代に遡る。}が近年注目を集めているが、これについても触れたい。 CとはもともとはDを発展させたものであり、F[^abort_f]という別名もある。 [^about_a]: Aの起源は室町時代に遡る。 [^about_c]: Cの起源は江戸時代に遡る。 [^about_d]: Dの起源はわからない。 [^about_f]: Fはおいしい。
rargs
を使って、sedの命令を作ります。生成されるのは以下の感じ
$ cat Sh*/v*52/annotation.md | tail -n4 | rargs -p "\[\^(.+)\]: (.+)" echo "s/([^^])\[\^{1}\]/\1\\\ footnote{{2}}/" s/([^^])\[\^about_a\]/\1\\footnote{Aの起源は室町時代に遡る。}/ s/([^^])\[\^about_c\]/\1\\footnote{Cの起源は江戸時代に遡る。}/ s/([^^])\[\^about_d\]/\1\\footnote{Dの起源はわからない。}/ s/([^^])\[\^about_f\]/\1\\footnote{Fはおいしい。}/
エスケープだらけで意味判らねえなおい。簡単に意味を書くと「行頭でない[^about_hoge]を\footnote{HOGE}に置換する」
です。\1
で後方参照しているのは「行頭でない」の[^^]
が一文字拾ってしまうからです。否定後読みとかならいらないのかな
PowerShellでも今回はsed
に食わせるスクリプトを生成することにします。
$ cat .\annotation.md -Encoding UTF8 | sls -Pattern '^\[\^(about_.)\]: (. +)' | % {"s/([^^])\[\^" + $_.Matches.Groups[1].Value + "\]/\1\\\footnote{" + $_.Matches.Groups[2].Value + "}/"} s/([^^])\[\^about_a\]/\1\\\footnote{Aの起源は室町時代に遡る。}/ s/([^^])\[\^about_c\]/\1\\\footnote{Cの起源は江戸時代に遡る。}/ s/([^^])\[\^about_d\]/\1\\\footnote{Dの起源はわからない。}/ s/([^^])\[\^about_f\]/\1\\\footnote{Fはおいしい。}/
sls
ではグルーピングもできます。MatchInfo
のGroups
でグループが参照できるので、それを使ってスクリプトを生成します。
Q6
TeXでは\label{hoge}
に対して\ref{hoge}
で参照が取れる。contents.tex
の中から\label
があるのに\ref
がない。またはその逆なものを検索してくださいという問題。
$ cat Sh*/v*52/contents.tex | grep -oPe "\\(ref|label)\{[^\{]+\}" | tr -d '\}' | sort -u |awk '{a[$2]=a[$2]" "$1;}END{for(x in a){print x, a[x]}}' FS=\{ | column -t | awk 'NF!=3{print $1}' | grep -f- -n Sh*/v*52/contents.tex 19:\subsection{ロボットの姿勢と座標系}\label{sub:pose} 116: \varphi_{c,t} \sim \mathcal{N}\left(\varphi_{c,t}^*,(3\pi/180)^2\right) \label{eq:phidist}\\ 157:\ref{sub:noise}項でモデル化した雑音から計算する。 170: \V{e}_{c,t,t'} = \V{x}_t' - \V{x}_t - \V{\mu}_{c,t,t'}\label{eq:e} 220:また、式(\ref{eq:unko})から、 242: \end{bmatrix} \label{eq:e2} 319:また、\ref{sub:noise}項の定義では、遠いところでランドマークを
途中のawkで、以下のようなデータを作りました。
$ cat Sh*/v*52/contents.tex | grep -oPe "\\\(ref|label)\{[^\}]+\}" | tr -d '\\}' | sort -u |awk '{a[$2]=a[$2]" "$1;}END{for(x in a){print x, a[x]}}' FS=\{ | column -t eq:ddist label ref sub:fullslam label ref sub:pose label fig:observation_noise label ref eq:e2 label eq:unko ref fig:coordinate label ref sub:noise ref eq:phidist label eq:psidist label ref fig:two_poses label ref fig:observation label ref eq:e label
labelがあるかrefがあるかの表です。あとはカラムの個数が足りない(=どちらかが足りない)ものについて検索をすれば終わりという感じ。
PowerShellではちょっとPowerShell感を使って解いてみます
$ cat .\contents.tex -Encoding UTF8 | sls '\\(ref|label)\{([^}]+)\}' | %{ $_.matches.groups[2].value + "::" + $_.matches.groups[1].value } | sort -Unique | group { ($_ -split "::")[0] } | ?{$_.count -eq 1} | %{ sls -Pattern $_.name -Path .\contents.tex -Encoding UTF8 } | sort -Unique contents.tex:116: \varphi_{c,t} \sim \mathcal{N}\left(\varphi_{c,t}^*,(3\pi/180)^2\right) \label{eq:phidist} \\ contents.tex:117: \psi_{c,t} \sim \mathcal{N}\left(\psi_{c,t}^*,(3\pi/180)^2\right) \label{eq:psidist} contents.tex:157:\ref{sub:noise}項でモデル化した雑音から計算する。 contents.tex:170: \V{e}_{c,t,t'} = \V{x}_t' - \V{x}_t - \V{\mu}_{c,t,t'}\label{eq:e} contents.tex:19:\subsection{ロボットの姿勢と座標系}\label{sub:pose} contents.tex:220:また、式(\ref{eq:unko})から、 contents.tex:242: \end{bmatrix} \label{eq:e2} contents.tex:275:$\theta$方向の共分散であり、式(\ref{eq:ddist}-\ref{eq:psidist}) contents.tex:319:また、\ref{sub:noise}項の定義では、遠いところでランドマークを
方針自体は一緒です。違うのは中間データとして、以下のようなものを作って
> cat .\contents.tex -Encoding UTF8 | sls '\\(ref|label)\{([^}]+)\}' | %{ $_.matches.groups[2].value + "::" + $_.matches.groups[1].value } | sort -Unique eq:ddist::label eq:ddist::ref eq:e::label eq:e2::label eq:phidist::label eq:psidist::label eq:unko::ref fig:coordinate::label fig:coordinate::ref fig:observation::label fig:observation::ref fig:observation_noise::label fig:observation_noise::ref fig:two_poses::label fig:two_poses::ref sub:fullslam::label sub:fullslam::ref sub:noise::ref sub:pose::label
これの各行に対し::
でsplit
した一個目をキーにGroup-Object
しています。こういった集計はやりやすくていいなあと思います。
Q7
$ cat Sh*/v*52/contents.tex | awk '/\\begin\{bmatrix\}/,/\\end\{bmatrix\}/{printf $0"@@@"}/\\end\{bmatrix\}/{print ""}' | awk '{print gsub("&","&"), $0}' | awk '$1==6{$1="";print}' | sed -z 's/@@@/ /g'
ほぼ先生の解答通り。awk '/begin/, /end/'
を最近AWK処方箋で読んだので、使えてよかったです
Q8
重複する文がcontents.tex
には存在するので、その位置を出力する問題。ぜんっぜんわからなかった。
終わりに
今回はQ1から時間ギリギリにしかできなくてやばかったですね。sed
のスクリプトを生成するっていうのはいかにもシェル芸的なので楽しいですね。でも、あんまり普段はやらない作業かもなぁと思いました。文章の修正とかをする人ならよくあるのかな?って感じです。
今回もとても楽しかったです。企画・開催ありがとうございました!!