bit

WindowsのVIMで開発しているスクリプトをリモートのLinuxで動作確認するために半自動でSCPする

というありがちなパターン。

WinSCPがインストールされている前提で、その keepuptodate コマンドでもいいんだけど、今回は反映タイミングは制御したかったので、初VIMスクリプトの練習として書いてみた。

といっても、パスセパレータのエスケープが面倒だったんで、この記事の隠れ主題として、VIMスクリプトの中でセパレータをどこで何個書けばよいかの備忘録というのがある。

下記スクリプト呼び出されている WinSCP スクリプト(sync.winscp)はリモートに接続して、syncしたりputしたりしてclose→exitするものであれば何でもよく、このVIMスクリプトと同じディレクトリに置いておくように記載している。

" Sync
let s:winscp = 'C:\\Program Files (x86)\\WinSCP\\WinSCP.exe'
let s:script_filepath = expand('%:h') . '\sync.winscp'

function! Sync()
  let l:script_filepath = substitute(s:script_filepath, '\\', '\\\\', 'g')

  let l:command =
\   printf('call system("\"%s\" /console /script=\"%s\"")',
\   s:winscp, l:script_filepath)

  execute l:command
endfunction

command! Sync :call Sync()

んで、VIMを起動したときに最初にこのスクリプトを source しておくと、開発したスクリプトをリモートのLinuxに持っていきたいときに :Sync とするだけでそれができる。

(追記)
Windowsでも、Cygwinなどの scp.exe がインストールされていてパスが適切に設定されていれば、:edit scp://~ でリモートのファイルを透過的に編集できるらしい。まあいいや。VIMスクリプトのいい練習になったのでよしとする。

部分クイックソート

久しぶりに勉強。配列の一部だけをソートする部分ソート(partial sort)。

参考にしたのは、ぐぐって見つけた論文と、ロゼッタコードのページ。たぶんこれでいいと思うけど。

sortRecursively(array, 0, array.length - 1, lowerBound, upperBound);


private static <T extends Compatible<T>>
sortRecursively(T[] array, int leftEnd, int rightEnd, int lowerBound, int upperBound) {

    int pivotIdx = selectPivot(array, leftEnd, rightEnd);

    int[] lrIdx = splitArrayIntoLandU(array, leftEnd, rightEnd, pivotIdx);

    if (lowerBound < lrIdx[0]) {
      sortRecursively(array, leftEnd, lrIdx[0], lowerBound, upperBound);
    }

    if (lrIdx[1] < upperBound) {
      sortRecursively(array, lrIdx[1], rightEnd, lowerBound, upperBound);
    }
}

private static <T extends Comparable<T>>
int[] splitArrayIntoLandU(T[] array, int leftEnd, int rightEnd, int pivotIndex) {

    T pivot = array[pivotIndex];

    while(leftEnd<= rightEnd) {
      while (array[leftEnd].compareTo(pivot) < 0) {
        ++leftEnd;
      }

      while (pivot.compareTo(array[rightEnd]) < 0) {
        --rightEnd;
      }

      if (leftEnd <= rightEnd) {
        swap(array, leftEnd, rightEnd);
        ++leftEnd;
        --rightEnd;
      }
    }

    return new int[] {rightEnd, leftEnd};
 }

これで lowerBound ~ upperBound の間だけがソートされる。メソッド selectPivot は leftEnd と rightEnd の間からピボットを取るようにする。

Rubyエンコーディング

Rubyを時々触るのだけれど、こんなプログラム:

# -*- coding: utf-8 -*-
puts "あいうえお"

を組んで、実行すると

PS D:\home\iwsttty\> ruby .\puts_japanese.rb
縺ゅ>縺・∴縺

こうなる。で、あれ?と思って、ああ「-U」オプション忘れてたと気づく。国産言語なのに、こんな単純なプログラムでさえ、日本語をJavaみたいによろしくやってくれない。
くやしいので、なぜこうなるのかというところを理解するために、とりあえず図にする。

左側が書き込みのとき、右側が読み込みのとき。矢印は実線と破線の二種類があって、前者はそのままバイト列が渡されること、後者は何らかの変換がされることを表わしている。
書き込みのときは、外部エンコーディングが明示的に設定されているかどうかで挙動が異なる(内部エンコーディングは関係ない)。設定されていなければ、Stringオブジェクトのバイト列がそのまま出力される。設定されていれば、文字列エンコーディングからそのIOオブジェクトの外部エンコーディングに変換されて出力される。明示的と言ったのは、EncodingのメソッドにEncoding.default_externalというのがあって、外部エンコーディングが設定されていないとあたかもこちらの値が使われるようなイメージがあるからであるが、書き込み時はこの値は関係ない。
読み込みのときは、内部エンコーディングが設定されているかどうかで挙動が異なる。設定されていなければ、入力されたバイト列は外部エンコーディングを仮定して、Rubyプロセス内部に読み込まれる。設定されていれば、さらに内部エンコーディングに変換される。
先ほどのEncoding.default_externalは、読み込み時で、かつそのIOオブジェクトに外部エンコーディングが設定されていない場合に用いられる。ニッチだ。
冒頭のプログラムに戻ると、Rubyは何もしないと標準出力オブジェクトSTDOUTのエンコーディングは内部、外部ともに設定されないため、UTF-8文字列を外部に出力すると、そのままPowerShellの端末に出力される。PowerShellのエンコーディングはディフォルトでは「日本語 (シフト JIS)」なので、文字化けする。

PS D:\home\iwsttty> [console]::OutputEncoding.EncodingName
日本語 (シフト JIS)

結局、STDOUTの外部エンコーディングが初期状態でnilなのがダメなんだろうな。せっかくEncoding.default_externalが適切に設定されているのに。

PowerShellでプロクシ設定

ぐぐっても意外と情報がなかったのでメモ。

> Set-Item -path Env:http_proxy -value http://proxy.youroffice.co.jp:7777
> $Env:http_proxy
http://proxy.youroffice.co.jp:7777
> gem install nokogiri
Fetching: nokogiri-1.5.5-x86-mingw32.gem (100%)
Successfully installed nokogiri-1.5.5-x86-mingw32
1 gem installed

ジョギング音楽

(2014/5/9) 新しく2014年バージョンを公開。→こちら

私がジョギングのときにiPodで聴いている曲を紹介。BPM 160前後の洋楽が中心。

曲名 アーティスト名 BPM リンク
Crawling Back To You Daughtry 151 iTunes / Youtube
Feelin' Way Too Damn Good Nickelback 156 iTunes
Over You Daughtry 156 iTunes / Youtube
Duca Chara 156
変わらないもの 奥華子 157 iTunes
Blurry Puddle of Mudd 157 iTunes / Youtube
Holding On to Heaven Nickelback 158 iTunes
Keep Holding On Avril Lavigne 161 iTunes
Some Say Sum 41 162 iTunes / Youtube
Keep It Together Puddle of Mudd 162 iTunes
What About Now Daughtry 162 iTunes
We Don't Have To Look Back Now Puddle of Mudd 163 Youtube
Some Day Nickelback 163 iTunes / Youtube
Don't Ever Let It End Nickelback 168 iTunes
Losing My Mind Daughtry 168 iTunes / Youtube

ついでに、ジョギングに向いているかはともかくBPM 160前後の曲の紹介。

曲名 アーティスト名 BPM リンク
ふでペン〜ボールペン 放課後ティータイム 153
働く男 ユニコーン 160
Woman Like You Lee Brice 160 Youtube
iYiY Cody Simpson 160 iTunes / Youtube
Sense Amanda Mair 165 Youtube
Got Me Good Cody Simpson 168 Youtube

このBPMは、BPM計測サービスで手動で測ってみたのだが、ちょっと感覚と違う。Blurry と Keep It Together は同じくらいだと思うんだけど。
まあいいや。参考まで。

(追記 2012/4/7) Nickelback のアルバムをiTunesで購入したので、二曲追加。
(追記 2012/4/14) iTunesへのリンクを追加 (別にアフィリエイトではない)。
(追記 2012/6/16) Cody SimpsonはBPM160前後の曲が多く探しやすいけど、中学生なんだよな、こいつ...。

ネットワークインタフェイス一覧

Linuxのネットワークインタフェイス一覧を取得する話。
ifconfig コマンドの出力がパースしにくい*1ので、もう少し簡単に取得できないかと調べた。ifconfig のソースコード*2読んだだけだが、役に立つ人もいるかもしれないので書いておく。
先にオチを言っておくと、パースするほうが簡単だった…。

ifconfig は、/proc/net/dev から読み取ったインタフェイス一覧*3と、ioctl(2) の SIOCGIFCONF リクエストで取り出した情報*4をマージしている。前者には IP エイリアス情報が含まれず、後者にはアクティブなインタフェイスしか含まれないからである。
話を元に戻すと、簡単に一覧を取得するには /proc/net/dev のほうはともかく、ioctl が厄介。ifconf 構造体を ioctl 関数に渡せばよいのだが、こいつが ifreq 構造体へのポインタを持っている。

struct ifconf
  {
    int ifc_len;                        /* Size of buffer.  */
    union
      {
        __caddr_t ifcu_buf;
        struct ifreq *ifcu_req;
      } ifc_ifcu;
  };

知らない人のために書いておくと、ioctl 関数は、(領域を割り当てた)構造体のポインタを渡すと、その構造体にリクエストしたデバイス情報を埋め込んで返してくれる。
Perl の ioctl 関数もまったく同じ。つまり、Perlでバッファ確保とそのポインタを渡す必要がある…。

*1:CPANにいろいろ転がっているのは知っている。

*2:[https://developer.berlios.de/projects/net-tools/:title=net-tools]

*3:lib/interface.c の if_readlist_proc関数を参照

*4:lib/interface.c の if_readconf関数を参照

続きを読む

ローマ字っぽいアルファベット表記を見つけるための正規表現

アルファベットの並びがローマ字っぽいものを見つけるための正規表現
人名がずらっと並んでいるときに、日本人名を見つけたかったので。

if (/^(\s*(((([bdghjkmnpstrz])\5?)?y?([ei]|[aou]h?))|ss?h[aiuo]|cc?h[aio]|tt?su|wa|fu|n)+){1,2}\s*$/i) {
  chomp;
  print $_, "\n";
}

gha(ぎゃ) とか wwa(っわ) とかは、ないだろと思って外しているので、意図するものが引っかからない可能性はある。逆に、Gianni とか、Hiseman とかもひっかかってしまうが、それは仕方ない。