第28回シェル芸勉強会に行ってきたので、その復習。 今回はLaTeXのファイルに対して、特定箇所の抽出やらを行っていく形式。

正直、かなり難しかった…。 前回もそうだったけど、ほとんどついていけなかった。 よくわからなかったトコについては、回答できた人の内容を分解して理解を進めることにする。

問題および模範解答はこちら。 問題で使用するファイルは、(1ファイルしかないけど)以下のコマンドでダウンロードすると良いだろう。

git clone https://github.com/ryuichiueda/ShellGeiData.git

Q1.

まずはQ1。これは簡単で、それぞれ以下のように回答できる。 sedでもいけるけど、とりあえずawk。

Q1-1.

awk '/\\begin{figure}/,/\\end{figure}/' contents.tex
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ awk '/\\begin{figure}/,/\\end{figure}/' contents.tex
\begin{figure}[htbp]
        \begin{center}
                \includegraphics[width=0.5\linewidth]{./figs/coordinate.eps}
                \caption{世界座標系とロボットの姿勢}
                \label{fig:coordinate}
        \end{center}
\end{figure}
\begin{figure}[htbp]
        \begin{center}
                \includegraphics[width=0.5\linewidth]{./figs/observation.eps}
                \caption{計測値}
                \label{fig:observation}
        \end{center}
\end{figure}
\begin{figure}[htbp]
        \begin{center}
                \includegraphics[width=0.5\linewidth]{./figs/two_poses.eps}
                \caption{ランドマークの計測値から2点の相対姿勢を求める}
                \label{fig:two_poses}
        \end{center}
\end{figure}
\begin{figure}[htbp]
        \begin{center}
                \includegraphics[width=0.8\linewidth]{./figs/observation_noise.eps}
                \caption{ランドマークの計測値の不確かさを表す共分散行列}
                \label{fig:observation_noise}
        \end{center}
\end{figure}

Q1-2.

Q1-1の内容をベースに、以下のようにコマンドを実行する事で回答できる。

awk '/\\begin{figure}/,/\\end{figure}/' contents.tex|grep -e includegraphics -e caption|xargs -n 2|awk -F[{}] '{print $4,$2}'
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ awk '/\\begin{figure}/,/\\end{figure}/' contents.tex|grep -e includegraphics -e caption|xargs -n 2|awk -F[{}] '{print $4,$2}'
世界座標系とロボットの姿勢 ./figs/coordinate.eps
計測値 ./figs/observation.eps
ランドマークの計測値から2点の相対姿勢を求める ./figs/two_poses.eps
ランドマークの計測値の不確かさを表す共分散行列 ./figs/observation_noise.eps

Q2.

第二章の第一文を抽出する、という問題。 今ひとつ問題を理解できてなかったのだが、以下のようにコマンドを実行することで回答が得られる(あまりキレイでは無いけど…)。

grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs | grep -Po 'section.+?。' | sed -n 's/^section{\([^"]*\)} //g;2p'
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs | grep -Po 'section.+?。' | sed -n 's/^section{\([^"]*\)} //g;2p'
平面上を移動し、向きを持ち、カメラでランドマーク観測ができるロボットで graph-based SLAMを実行する方法を考える。

パイプごとの各コマンドだが、分解すると以下のようになっている。

# コメントを削除
grep -v ^% contents.tex

# 「\section」から、「。」が出て来る行までを抽出する
grep -v ^% contents.tex | awk '/\\section/,/。/'

# 改行を削除してやる
grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs

# 「\section」から、「。」までを、1行として抽出してやる
grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs | grep -Po 'section.+?。'

# 「\section{*} 」を削除して、2行目(第2セクション)のみを抽出する
grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs | grep -Po 'section.+?。' | sed -n 's/^section{\([^"]*\)} //g;2p'
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ # 「\section」から、「。」が出て来る行までを抽出する
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ grep -v ^% contents.tex | awk '/\\section/,/。/'
\section{はじめに}

この文章は、\cite{grisetti2010}などのチュートリアルを見ても数式の細かいところが分からない
graph-based SLAMについて、
実際の計算方法を細かく解説するためのものである。
\section{問題}

平面上を移動し、向きを持ち、カメラでランドマーク観測ができるロボットで
graph-based SLAMを実行する方法を考える。ランドマークは環境にいくつか存在し、
\section{graph-based SLAMの実装例}

実装の一例を示す。
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ # 改行を削除してやる
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs
section{はじめに} この文章は、cite{grisetti2010}などのチュートリアルを見ても数式の細かいところが分からない graph-based SLAMについて、 実際の計算方法を細かく解説するためのものである。 section{問題} 平面上を移動し、向きを持ち、カメラでランドマーク観測ができるロボットで graph-based SLAMを実行する方法を考える。ランドマークは環境にいくつか存在し、 section{graph-based SLAMの実装例} 実装の一例を示す。
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ # 「\section」から、「。」までを、1行として抽出してやる
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs | grep -Po 'section.+?。'
section{はじめに} この文章は、cite{grisetti2010}などのチュートリアルを見ても数式の細かいところが分からない graph-based SLAMについて、 実際の計算方法を細かく解説するためのものである。
section{問題} 平面上を移動し、向きを持ち、カメラでランドマーク観測ができるロボットで graph-based SLAMを実行する方法を考える。
section{graph-based SLAMの実装例} 実装の一例を示す。
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ # 「\section{*} 」を削除して、2行目(第2セクション)のみを抽出する
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ grep -v ^% contents.tex | awk '/\\section/,/。/' | xargs | grep -Po 'section.+?。' | sed -n 's/^section{\([^"]*\)} //g;2p'
平面上を移動し、向きを持ち、カメラでランドマーク観測ができるロボットで graph-based SLAMを実行する方法を考える。

その他、ebanさんの回答が短いので参考。

Q3.

脚注の部分を全て抽出するという問題。最初に引っかかる脚注内で{}がネストしているため、結構難しい。
とりあえず、文章内で脚注の終わりは「。}」で統一されているため、これを利用して抽出する(ちゃんとやるならパーサー作らないと駄目っぽい)。

sed -z 's/\n//g' contents.tex | grep -oP '(\\footnote{.+?。})'
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ sed -z 's/\n//g' contents.tex | grep -oP '(\\footnote{.+?。})'
\footnote{この仮定は実用上強すぎるが、実際には、後の計算式から分かるように、2つの姿勢間での値$\psi_{c,t}, \psi_{c,t'}$の差だけが分かれば良い。例えば、2点間で得られた画像の向きを画像処理から割り出すなどの処理で、この差は得られる。}
\footnote{$「10$[\%]」は変数にすべきだが、記号が増えて理解の妨げになるので固定値として説明する。}
\footnote{おそらく$\psi$は$\theta$で置き換えられるので$\psi$を使わない実装もできるが、まだ自分自身では検証していない。}
\footnote{小さい角度なので、$\sin(3\pi/180)$は$3\pi/180$に近似しても良い。}
\footnote{固定しないと世界座標系が決まらない。}

Q4.

各sectionの内容を、そのsection名で別ファイルに保存するという問題。 awkで、対象のsection名を抜き出し、そこにリダイレクトさせるようにすることで対応ができる。 時間内に回答することができなかったので、ebanさんの回答を分かりやすくして理解する。

awk -F'[{}]' '/\\section/ {name=$2}{print > name".tex"}' contents.tex
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ ls -la
合計 32
drwxrwxr-x  2 blacknon blacknon  4096  4月 23 08:48 .
drwxrwxr-x 16 blacknon blacknon  4096  4月 22 20:52 ..
-rw-rw-r--  1 blacknon blacknon 21781  4月 22 20:52 contents.tex
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ awk -F'[{}]' '/\\section/ {name=$2}{print > name".txt"}' contents.tex
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ ls -la
合計 60
drwxrwxr-x  2 blacknon blacknon  4096  4月 23 08:48 .
drwxrwxr-x 16 blacknon blacknon  4096  4月 22 20:52 ..
-rw-rw-r--  1 blacknon blacknon 21781  4月 22 20:52 contents.tex
-rw-rw-r--  1 blacknon blacknon 15432  4月 23 08:48 graph-based SLAMの実装例.txt
-rw-rw-r--  1 blacknon blacknon   527  4月 23 08:48 はじめに.txt
-rw-rw-r--  1 blacknon blacknon  5822  4月 23 08:48 問題.txt

最初に見たときはだいぶ混乱したが、間にスペース入れたり一部の記号({)を除外したら分かりやすくなった。

Q5.

「◯◯座標系」というキーワードを抽出する、という問題。 ◯◯に入るのはカタカナか漢字という事なので、それ以外を除外してやればいけるようだ。

とりあえず、grepで「[^ぁ-ん]」でひらがな以外、という風に指定できるので、それに記号や句読点をあわせて以下のようにコマンドを実行することで除外が可能だ。

grep -oP [^ぁ-ん、「{]+?座標系 contents.tex | sort -u

しかし、ebanさんの回答のように、以下のようにPerlの正規表現を利用することで、カタカナや漢字のみを指定してgrepすることができるらしい。 (知らなかった…)

grep -Po '(\p{Katakana}|\p{Han})+座標系' contents.tex | sort -u
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ grep -oP [^ぁ-ん、「{]+?座標系 contents.tex | sort -u
ロボット座標系
計測座標系
世界座標系
blacknon@BS-PUB-DEVELOP:~/ShellGeiData/vol.28$ grep -Po '(\p{Katakana}|\p{Han})+座標系' contents.tex | sort -u
ロボット座標系
計測座標系
世界座標系

Q6.

この辺からもう解けなかった。 文章の段落の頭に全角スペースを入れる、という内容。 前にやってたこちらの内容を利用してなんとかできないかと思ったのだが、時間内にはできなかった。

grep -v ^% contents.tex | awk -vRS= -vORS='\n\n' '{printf " ";print $0}' contents.tex

(多分)このやり方でできている…はず。 こちらのebanさんの回答でも同様のやり方を取っている(もっと洗練されているけど)。

Q7.

各段落の改行を削除する、という内容。 正直わからんかった。 多分、ebanさんのこの回答(perl)が一つの答えなのかなー…というぼんやりとした状態。

Q8.

目次というか、各詳節項のリストをワンラインで作成するという内容。 とりあえずゴリゴリやっていくしか無いようだ。 もうこの時点で疲れ切ってたので、時間内ではできなかった。 とりあえず復習で出した答え。 (ginjiroさんのこちらの回答も参考にさせていただいた)

grep -P '^\\.*?section{' contents.tex | sed 's/\\label.*//g;s/section{/section@/;s/}$//g' | awk -F'@' 'BEGIN{a=b=c=0} /^\\sec/{a++;ss=0;print a,$2} /\\subsec/{b++;c=0;print a"."b,$2} /\\subsub/{c++; print a"."b"."c,$2}'

今回、とりあえずえらい難しかった…。 全然ついてけてなかったので、次回はもうちょい解けるように精進しないとなぁ…(毎回玉砕してこれ言ってる気がするけど)