読者です 読者をやめる 読者になる 読者になる

空白行の重複を削除する

Ruby

Rubyワンライナーone-linerを書く方法のまとめhttp://blog.lilyx.net/2007/11/29/writing-one-liner-in-ruby/という記事があって、いろいろ参考になります。
わたしが一番よく使うのは、計算機がわりで、3の10乗は? とか、F000から3A20を引いたらどう?とかです。
ruby -e'puts 3**10' => 59049
ruby -e'puts 0xf000 - 0x3a20' => 46560
ruby -e'puts 0b1000' => 8
ruby -e'puts 0o66' => 54

rubyのあとの'-e'というのがexecute(実行する)という意味で、そのあとのシングルクオートに囲まれた部分がrubyで実行されます。16進法や2進法の数字でも頭に0xとかつけてあげれば計算してくれる。逆に10進法の数字を16進法であらわしたいときは、ちょっと工夫。printfを使います。

ruby -e'printf "%d is %x in hex. \n", 65535 , 65535' => 65535 is ffff in hex.

上記のサイトには、テキスト処理の話が載っていて、rubyのあとに-pをつけると、

while gets
  …
  print $_
end

と書いたと同じことができる、とあります。つまり、一行ずつ読み込んで、処理をしてアウトプットする(上記のprint $_)。-pはすべてアウトプット、-nはアウトプット指示していなものはアウトプットしない(上記のprint $_がないもの)。

ruby -p -e'gsub(/6/,"N")' temp.txt
とすれば、一行ずつ読み込んで、その行の中に"6"があれば、"N"に置き換える。

grepのようにある文字列が含まれているかどうか、含まれていれば何行目かを表示して、その行を表示したい場合。-pでなく-nを使います。
ruby -n -e ' print "line #{$.}: #{$_}" if $_ =~ /searchword/' temp.txt

すべての大文字を小文字にしたいとき。下記のdowncase!のように"!"が必要です。
ruby -p -e'$_.downcase!' temp.txt

さて、問題の空行を削除するrubyワンライナー。空行(\nしか含まない行)を出力しないというのなら、下記のように空行以外だけプリントアウト、というプログラムでOK。
ruby -n -e'print if $_!="\n"' temp.txt

空行の連続を削除したい、とか、全体をソートしたい、とかの処理は、一行ずつではできませんので、別の工夫が必要。私はFile.open('filename'){}で読み込んで処理をして、アウトプットしています。試行錯誤中。

同じ内容の行の連続をひとつにするワンライナー(uniqを使うと連続でない行も削除されてしまうのでダメ)
ruby -e'File.open(ARGV[0]){text = ;last=""; while gets;text.push($_) if $_!=last; last = $_; end;puts text}' temp.txt
(textという空のarrayを作って、一行ずつ前の行と比べながら、収納(push)していく。ファイル全部やり終わってから、アウトプット。)

sortするワンライナー
ruby -e'File.open(ARGV[0]){text = ; while gets;text.push($_); end; puts text.sort!}' temp.txt
(textという空のarrayに全行を収納し、sortをかけてアウトプット。)

いかがでしょうか。

追記:File.open(ARGV[0]){}は不要なことが判明。上記の二つは下記のように書けます。
ruby -e'text = ;last=""; while gets;text.push($_) if $_!=last; last = $_; end;puts text' temp.txt
ruby -e'text =
; while gets;text.push($_); end; puts text.sort!' temp.txt

同じ考え方で、ファイルの最初の5行を出力(head.rb)、最後の5行を出力(tail.rb)なんかも作れますね。
ruby -e'text = ; while gets;text.push($_); end; puts text[0..4]' temp.txt
ruby -e'text =
; while gets;text.push($_); end; puts text[-5..-1]' temp.txt

同じ考え方で行数カウント。
ruby -e'text = []; while gets;text.push($_); end; puts text.length' temp.txt
これは下記のようにも書けると、ruby phrasebookにありました。
ruby -n -e'END{ puts $. }' temp.txt

追記:はやりのFizz Buzz問題もワンライナーで。fizzbuzz.rb
ruby -e'for i in (1..100) do if i % 15 == 0; puts "FizzBuzz"; elsif i % 3 == 0; puts "Fizz"; elsif i % 5 == 0; puts "Buzz"; else puts i; end; end'

追記:テキストに行番号をつけるワンライナー
ruby -ne'printf("%2d : %s", $., $_)' temp.txt