ワンライナーで繰り返し文字列のローテーションを行わせる
Pocket

先日、Twitter上でそういった処理について盛り上がってた(気づいたときにはすでに終わってた)ので、復習がてら実際に解いたり人の回答を解析したりしてみることにした。
とりあえずebanさんの解答がすごすぎてよくわからん…。ので、分解してみる。

「響け!ユーフォニアム」という文字列を循環(巡回シフト)させて以下のような出力を得る、というお題。

響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
ム響け!ユーフォニア
Sponsored Links

sedでやるパターン

前にシーザー暗号について調べたときの方法が利用できそうなので、sedで解いてみる。
とりあえず頭からechoで渡す必要がないなら、以下で回答できる(解き方として有りなのかは不明だが…)。

for i in {0..9}; do echo "響け!ユーフォニアム" | sed -E "s/^(.{$i})(.*)/\2\1/" ; done;
[root@BS-PUB-CENT7-01 ~]# for i in {0..9}; do echo "響け!ユーフォニアム" | sed -E "s/^(.{$i})(.*)/\2\1/" ; done;
響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
ム響け!ユーフォニア

 

長さを10文字に決めうちにしているのでちょっといただけないかも。
書き方は汚いけど、元の文字列の長さに応じて処理させる場合は以下。

S="響け!ユーフォニアム";for i in `eval echo {0..$(($(echo -n $S|wc -m) -1 ))}`; do echo $S | sed -E "s/^(.{$i})(.*)/\2\1/" ; done;
[root@BS-PUB-CENT7-01 ~]# S="響け!ユーフォニアム";for i in `eval echo {0..$(($(echo -n $S|wc -m) -1 ))}`; do echo $S | sed -E "s/^(.{$i})(.*)/\2\1/" ; done;
響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
ム響け!ユーフォニア
[root@BS-PUB-CENT7-01 ~]# S="響け!ユーフォニアムだ";for i in `eval echo {0..$(($(echo -n $S|wc -m) -1 ))}`; do echo $S | sed -E "s/^(.{$i})(.*)/\2\1/" ; done;
響け!ユーフォニアムだ
け!ユーフォニアムだ響
!ユーフォニアムだ響け
ユーフォニアムだ響け!
ーフォニアムだ響け!ユ
フォニアムだ響け!ユー
ォニアムだ響け!ユーフ
ニアムだ響け!ユーフォ
アムだ響け!ユーフォニ
ムだ響け!ユーフォニア
だ響け!ユーフォニアム

 

ちなみに、以下ebanさんの回答。
ラベルを使っているようなのだが、このままだと正直よくわからないので分解してみる。

echo 響け!ユーフォニアム | \
sed '
 :a # ラベル
 p # 処理をプリントする
 s/\(.\)\(.*\)/\2\1/ #置換処理。ここは通常の使い方と変わらない
 /^ム/!ba # 頭が「ム」で始まらない場合はaラベルに戻る
'
[root@BS-PUB-CENT7-01 ~]# echo 響け!ユーフォニアム | sed ':a;p;s/\(.\)\(.*\)/\2\1/;/^ム/!ba'#シェル芸
響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
ム響け!ユーフォニア
[root@BS-PUB-CENT7-01 ~]# echo 響け!ユーフォニアム | sed '
  :a # ラベル
  p  # 処理をプリントする
  s/\(.\)\(.*\)/\2\1/ #置換処理。ここは通常の使い方と変わらない
  /^ム/!ba # 頭が「ム」で始まらない場合はaラベルに戻る
'
響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
ム響け!ユーフォニア

 

もう一個のパターンについても分解してみる。

echo 響け!ユーフォニアム | \
sed -ne'
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #'{0..9} #行番号を指定

 

これだけだと正直よくわからない…
set -x使ってデバッグするとわかるのだが、さらに分解するとこんな感じらしい。

echo 響け!ユーフォニアム | \
sed -ne'
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #0
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #1
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #2
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #3
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #4
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #5
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #6
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #7
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #8
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #9
'
blacknon@BS-PUB-UBUNTU-01:~$ set -x
blacknon@BS-PUB-UBUNTU-01:~$ echo 響け!ユーフォニアム | \
> sed -ne'
>   p # プリント
>   s/\(.\)\(.*\)/\2\1/ # 置換
>   #'{0..9} #行番号を指定
+ echo 響け!ユーフォニアム
+ sed '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #0' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #1' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #2' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #3' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #4' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #5' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #6' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #7' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #8' '-ne
  p # プリント
  s/\(.\)\(.*\)/\2\1/ # 置換
  #9'
響け!ユーフォニアム
け!ユーフォニアム響
!ユーフォニアム響け
ユーフォニアム響け!
ーフォニアム響け!ユ
フォニアム響け!ユー
ォニアム響け!ユーフ
ニアム響け!ユーフォ
アム響け!ユーフォニ
ム響け!ユーフォニア

 

こんな処理方法があるのか…

 

perlでやるパターン

次はperl。
こちらもebanさんの回答を元に分解して理解してみる。

echo 響け!ユーフォニアム | perl -CIO -e 'print,s/(.)(.*)/\2\1/ for(<>)x10'

 

まず、「-CIO」オプションのそれぞれのざっくりとした効果は以下のようだ。(よくわかってない)
とりあえず、下のページと「perldoc perlrun」コマンドの結果から。
参考:Perl のワンライナーについての個人的なメモ – BitWalker

  • -C … 文字エンコードをよしなにしてくれる(Unicode機能の有効化)
  • -IO … モジュールの検索PATHの追加(-Iディレクトリ)

 

で、その後の処理について分解する。

echo 響け!ユーフォニアム | \
perl -CIO -e '
  print s/(.)(.*)/\2\1/ # 置換処理を行う
  for(<>)               # 標準出力から得られたラインをループさせる
  x10                   # x 数字でループ回数を指定する
'

 

理解しきれてないが、どうやらこういった処理になってるようだ。

 

jq使うパターン

jq使うパターンもあるようだ。
この短さで長さが変動した場合でも対応しているようだ。すごい…。

echo 響け!ユーフォニアム | jq -Rr 'range(length)as$r|(.*2)[$r:$r+length+1]'

 

分解した結果が以下。
正直、全然よくわからない…

echo 響け!ユーフォニアム | \
jq -Rr '
  range(length)as$r |    # 文字数を取得して$rに代入
  (.*2)[$r:$r+length+1]  # 置換してずらしていく(ここがよくわからない)
'
blacknon@BS-PUB-UBUNTU-01:~$ echo 響け!ユーフォニアム | \
> jq -Rr '
>   range(length)as$r |    # 文字数を取得して$rに代入
>   (.*2)[$r:$r+length+1]  # 置換してずらしていく(ここがよくわからない)
> '
響け!ユーフォニアム響
け!ユーフォニアム響け
!ユーフォニアム響け!
ユーフォニアム響け!ユ
ーフォニアム響け!ユー
フォニアム響け!ユーフ
ォニアム響け!ユーフォ
ニアム響け!ユーフォニ
アム響け!ユーフォニア
ム響け!ユーフォニアム

 

※2016/10/28 追記

ちょっと違ってたようだ。一行目の最後に「響」が入っちゃってる。
実際には以下のコードを実行するとよさそうだ。

echo 響け!ユーフォニアム | jq -Rr 'range(length)as$r|(.*2)[$r:$r+length]'

 

 

…なんか、「ebanさんの手法を学ぶ」みたいな内容になってしまった。
とりあえず、jq使いこなせればこんな事までできるとは知らなかったので色々いじってみようと思う。

 

Pocket

Written by blacknon

インフラ系のSE。一時期はプログラマ。 仮想化とオープンソースに興味あり。一日中寝てたい今日このごろ。 スペインとかで働きたいなぁ…(シエスタがあるので)

Leave a Comment

メールアドレスが公開されることはありません。