Kotlin1.2.50がリリースされていた

Kotlin1.2.50がリリースされていた

1.2.50になったからと言って何が新しくなったのかわからないが、
せっかくリリースされたので、今日のツールはKotlinで作る。
いつもなら、チョチョイとpython3を使うところだが。

ツールの仕様

日々の積み重ねで480万レコードになってしまったダンプファイルがある。
そのファイルはタブで区切られていて、特定のカラムの中の文字列の最大長が何文字か調べたい。

Pythonでならこう作る

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import codecs

with codecs.open('out1.txt', 'w', 'utf-8') as w1:
  with codecs.open('out2.txt', 'w', 'utf-8') as w2:
    with codecs.open('in.txt', 'r', 'utf-8') as r:
      for line in r:
        arr = line.strip().split('\t')
        if len(arr) >= 4:
          c0, c1, c2, c3 = arr[0:4]
          if len(c2) > 10:
            w1.write('{:03d}\t{}\t{}\n'.format(len(c2), c0, c2))
          if len(c3) > 10:
            w2.write('{:03d}\t{}\t{}\n'.format(len(c3), c0, c2))
        else:
          print('?[{}][{}]'.format(len(arr), line.strip()))

なかなか簡潔に書ける。
withの入れ子が深いけど、これくらいの長さなら気にしない。
適当なサーバで実行したら、480万レコードのファイルを調査するのに50秒かかった。

Kotlinで作ると

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.File

File("out1.txt").bufferedWriter().use { w1 ->
  File("out2.txt").bufferedWriter().use { w2 ->
    File("in.txt").forEachLine {
      val arr = it.split('\t')
      if (arr.size >= 4) {
        val (c0, c1, c2, c3) = it.split("\t")
        if (c2.length > 10) {
          w1.write("%03d\t%s\t%s\n".format(c2.length, c0, c2))
        }  
        if (c3.length > 10) {
          w2.write("%03d\t%s\t%s\n".format(c3.length, c0, c3))
        }  
      } else {
        println("?[%d][%s]".format(arr.size, it))
      }  
    }  
  }
}

閉じカッコの分、Kotlinの方が長くなってしまうが、pythonと同様に簡潔に書ける。
pythonのときと同じサーバで実行したら、同じ480万レコードのファイルを調査するのに3秒かかった。
Kotlin(java vm?)速い。

まとめ

最近、またpythonでツールを作ることが多くなっていたが、
Kotlinでの実装もなかなか楽しい。

処理速度がとても速い事にも驚いた。pythonに高速な印象はなかったが
ツールだったので、あまり遅さを気にしていなかった。
しかし、Kotlinがここまで速いのであれば、データ量に応じて率先してKotlinを使ってもいいのかもしれない。
.ktsであれば、コンパイルの手間もなくて意外と簡単に使うことができるので。

同じタグの記事
同じカテゴリの記事

PowerShell

PowerShell

エクスプローラーで、シフトキーを押しながら右クリックしたら
「PowerShellウィンドウをここに開く(S)」というメニューが存在したので、利用してみた。

環境変数の設定の仕方がわからない。

環境変数の設定

pythonを呼び出したかったので、PYTHONHOMEとPATHにpythonのパスを追加する。

1
2
$env:PYTHONHOME="C:\usr\python3"
$env:PATH="$env:PYTHONHOME;$env:PATH"

SETはいらないようだ。
$の後ろの区切りがあいまいなときは{}で括ってもよいようだ。

1
$env:PATH="${env:PYTHONHOME};${env:PATH}"

なかなか面白い。

環境変数の呼び出し

PATH環境変数の設定内容を確認する。

1
echo $env:PATH

プログラムの終了コードがわからない

ERRORLEVELではないらしい。

$LASTEXITCODE
で取得できる。

また、$?でTrue or Falseを受け取ることができる。

まとめ

ちなみに、シフトキーを押しながら右クリックしたとき、
Windows7では、
「コマンド ウィンドウをここで開く(W)」
だった。

マイクロソフトの方針としては、コマンドプロンプトよりPowerShellを使いなさいということなのだろうか。
あまり関係はないが、Windows10の「ここに開く」よりも、Windows7の「ここで開く」の方が日本語として正しい気がする。

PowerShellはコンソールに色がついたり、.NET Frameworkのオブジェクトを呼び出せたり、使いこなせるようになれば、いろいろラクできそうだ。

.NET Frameworkを使うような大きな作業をしなくても、タブキーによるパス補完で最後に”\”が付いてくれるだけでも、相当便利になっている。
コマンドプロンプトの頃は、タブ補完後に\をタイプしてから次の文字を入力していたのに、これからはタブ補完後、すぐに次の文字が入力できる。素晴らしい。

同じタグの記事
同じカテゴリの記事

JRubyを始める

Ruby(JRuby)を始める(始めた)

Javaのサードパーティー製APIをスクリプトから呼びたくて始めたJython。
python言語は容易に学習でき、あっさり使えるようになったが、
日本語が出現するたびに悩むことになる。
・Javaで取得した任意の文字コードの文字列を加工しようと思ったとき
・Javaで取得した任意の文字コードの文字列をcodecs.openで出力しようとしたとき
これは、Jythonでなくても、python2.7でも同様に苦労することになった。
str文字列と、unicode文字列の違いで実行時エラーになってしまう。
Jythonがpython3になってくれれば…
Jythonはメンテナンスが止まっていそうなので、他の言語に逃げることに。

Kotlinはコンパイルもできるが、スクリプトでも実行できるので、Kotlinに挑戦した。
Kotlinは優れている。いろいろなロジックを簡潔に書けるようになっている。
lambdaも便利だし、型推論も便利。SmartCastも理にかなっている。null safeなところも良い。
しかし、スクリプトとして少し使いたいだけの時は、ちょっと面倒。
Javaで作られたモジュールはreturn Mapだが、それは暗黙にMapと決まっているとき、キャストせずに使いたい。
null safeなKotlinだけど、Javaで作られたモジュールは、躊躇せずnullを返してくる。
Kotlinで完結させるなら良いかもしれないけど、やはりサードパティーのJavaAPIを使おうと思うと…

そこで、JRubyを使うことにした。
rubyの構文は独特な気がしたので、なかなか手を出せなかったが遂にこの時が来た。
perlが得意だったこともあるため、使ってみると懐かしさもあった。
学習の順番が良かったかもしれない。Kotlinでlambdaの良さを感じた後だったので、
rubyのlambdaが心地よい。

ここが良いruby

rubyを使っていて、ここが良いと思ったこと。

unless

ifを否定で使いたいとき、ifが「もし~ならば」に対して、unlessは「もし~でなければ」と使える。

1
2
3
4
5
a = 1
b = 2
unless a == b
    puts "not equal."
end

perlみたい。

文字列への変数展開

“#{var_name}”とすることで、文字列に変数を展開できる。

1
2
3
4
var_name = "test value"
puts "TEST1:[#{var_name}]"
puts "TEST2:[#{var_name.size}]"
puts "TEST3:[#{var_name.upcase}]"

Kotlinみたい(Kotlinは$だけど)。

n回繰り返しが簡単

10.timesで10回繰り返しが書ける。

1
2
3
10.times do |i|
    puts i
end

pythonも簡単だけど、rubyはもっと簡単。

1
2
for i in range(10)
    print(i)

pythonはブロックをインデントで表現できるので、結構短くコーディングできる。

メイン処理

スクリプトなので、スクリプトの先頭から処理が走ってしまうが、
直接実行したときのみ実行されるメソッドを定義する。

1
2
3
if __FILE__ == $0
    puts "Main"
end

pythonでも似たような感じ

1
2
if __name__ == '__main__':
    print("Main")

pythonはブロックの終端を書かなくて良いのが素敵。

まとめ

JRubyはなかなか心地よい。
構文はシンプルで、面倒が少ない。
do endは慣れる必要があるが、その程度だと思う。

しかし、サードパーティのJavaAPIを呼ぶこととなると、少し面倒なところもある。
APIがその先で読んでいるAPIのjarが読めないことがある。
JRubyはCLASSPATHを理解してくれて、そこからライブラリを探して勝手に動いてくるのだが、
たまに、明示的にrequire “xxxx.jar”しなてくはならない時がある。

JRubyを通じてrubyの使い方が理解できたので、それはそれで良かったのだが、
サードパーティJavaAPIを呼び出すのは、結果的にKotlin+Java8になりそう。

dll hellならぬjar hellに耐性があるのはKotlin+Java7(8以降)だと思う。

同じタグの記事
同じカテゴリの記事

perl正規表現で制御コードを除去する

perl正規表現で制御コードを除去する

RSSの収集をオリジナルのプログラムで行っている。
稀に制御コードが入っていることがあった。
制御コードが入っていると、オリジナルプログラムで利用しているXML::Simpleが異常終了してしまう。

なので、不要な制御コードを除去してからXML::Simpleを利用したい。

1
2
3
4
5
6
7
8
use LWP::Simple qw(get);
use XML::Simple;

my $url = "http://www.xxx.yyy/feed.rdf";
my $xml = get($url);
$xml =~ s/[[cntrl:]]//g;
my $xs = Xml::Simple-new;
my $obj = $xs->XMLin($xml);

これで制御コードが入ったRSSでも処理できるようになった。

同じタグの記事
同じカテゴリの記事