連続する数列をハイフンでまとめるシェルスクリプト
おもしろい!こうゆう問題が大好き。実用的であり、かつ頭の体操になる。
問題
並んだ数字を確認用にわかりやすくする為に、ソートされた数字の列をハイフンで繋ぐにはどうすればよいでしょうか?
数列は見づらいものです。ただ数字を並べているだけでは、ソートしてもどの数字が抜けているかを判断するために、順に目で追ってチェックする必要があります。
rubyではそういった配列をわかりやすく表現する為に「1...3」と表現する方法が用意されているのですが、利用者は、「1 2 3 5」というような数字の羅列を入れてくるかもしれません。さて、rubyでこれらをハイフンで繋ぐためにはどのように処理する必要があるでしょうか。
仕様
- 数値は、半角スペースで区切られた文字列で渡されます。
- 続いている部分は、最初の数値と最後の数値を-(ハイフン)で繋いだ表記にします。
- 連続が1回の場合(前の数も後ろの数も連続でない)は、-(ハイフン)では繋ぎません。
- 出力は、「,」(カンマ)と半角スペースで区切られた文字列でなければなりません。
例
"1 2 3" => "1-3." "1 2 3 5 7 8" => "1-3, 5, 7-8." "1 3 4 5 7" => "1, 3-5, 7."Rubyでどう書く?:連続した数列を範囲形式にまとめたい - builder by ZDNet Japan
- Rubyでどう書く?:連続した数列を範囲形式にまとめたい - builder by ZDNet Japan(2008/04/17 Ruby 元記事)
- Ruby で、連続した数列を範囲形式にまとめてみる : フッ君の日常(2008/04/21 Ruby)
- 索引の連続ノンブルをまとめる - 名もないテクノ手(2011/01/25 Ruby)
- Illustrator CS4でのfile pathの取得&perlで索引の連続ノンブルをまとめる | こざくらラボ(2012/06/28 Perl)
- [Perl] 索引の連続ノンブルをまとめるに挑戦 | キッズプレート、パスタおかわり 〜ひらくんと中宇宙戦争(2012/07/19 Perl)
すでに、RubyとPerlのサンプルが出揃っている。自分は何を使おうか?と考え、最も基本的なシェルスクリプト(sh)でやってみようと思い立った。shならほとんどすべての環境で動くことを期待して。自分が手作業行う時の頭の中の手順を、素直にコードにしてみた。
- hyphen_num.sh
#!/bin/sh res='' mode=',' last=$1 shift while [ -n "$1" ] do if [ `expr $1 - $last` -eq 1 ]; then [ "$mode" = "-" ] || res="${res}${last}-" mode='-' else res="${res}${last}," mode=',' fi last=$1 shift done res="${res}${last}" echo $res
- テストしてみた。
$ hyphen_num.sh 1 2 3 1-3 $ hyphen_num.sh 1 2 3 5 7 8 1-3,5,7-8 $ hyphen_num.sh 1 3 4 5 7 1,3-5,7
- 問題のサンプルとは若干違っているが、できた!
- カンマの後ろにスペースはない。
- 数列の終わりにピリオドはない。
なるほどー。
#!/bin/bash # or #!/bin/ksh read i s=${i%% *} let p=x=s-1 for n in $i x; do ((n-p-1)) && { ((p-x)) && o=$o-$p o=$o,\ $n x=$n } p=$n done o=$s${o#-$s} echo ${o%, x}.連続する数列をハイフンでまとめるピュアシェルスクリプト - ダメ出し Blog
% echo 0 1 2 3 5 7 8 23 24 25 50 100 101 102 103 110 | \ awk '{a=$1;for(i=0;b=_$++i;a=b)if(a+1==b)$i=-$i;OFS=",";gsub(/,-([0-9]+,-)*/,"-")}1' 0-3,5,7-8,23-25,50,100-103,110Just another Ruby porter, 2013-11-c
echo 1 2 3 5 7 8 | tr " " "\n" | awk '{printf a==$1-1?"-"$1:","$1;a=$1}' | sed 's/^-//' | sed 's/-[^,]*-/-/g' なんか悔しい仕上がり
— gori.sh/140コロニー/aoki (@RobustHunter) 2013, 11月 27
echo $@|xargs -n 1 echo|awk '$1!=l+1{print "/"}l=$1'|tr \\n/ \ \\n|awk 'NF>1{print $1"-"$NF}NF==1{print $1}'|tr \\n ,|sed 's/,$/./;s/,/, /g'
— USP MAGAZINE (@uspmag) 2013, 11月 27