置換の選択肢

Rubyでは文字列置換にはいくつも選択肢がある.

  1. #{}で式評価
  2. % 記法でハッシュ渡し
  3. String.gsub()でハッシュ渡し
  4. Kernel#format()
  5. Kernel#sprintf()


どう使い分ければいいのだろう?というのは,HTMLでのマークアップにはダブルクォーテーションがあるため,文字列中に変数展開をするとHTML片がまことみにくいことになる.なんとかならないものだろうか? 回答は以下.

単なる置換の場合

'<a href="' + val + '"></a>'   # もっとも原始的

"<a href=\"#{val}\"></a>"         # 式展開,しかし,バックスラッシュが醜い

%(<a href="#{val}"></a>)          # %記法ダブルクォート   ...(1)変数の場合; こうするしかないのか?
'<a href="%s"></a>' %  val        # String#% 書式付文字列 ...(2) フォーマット付
'<a href="%s_%02d.jpg"></a>' %  [val, 1]    
                                  # String#% 書式付文字列 ...(2)' フォーマット付(複数引数)
                                  # これらは,format()やsprintf()と実質同じ.

'<a href="{val}"></a>'.gsub(/\{(.*?)\}/){|word| vals[$1]}  
                                  # String#gsub(re,&)     ... (3) キーが文字列の辞書の場合(JSONなど)
                                  # パフォーマンス悪そう

'<a href="%{val}"></a>' % { :val => "sample.jpg"}
'<a href="%{val}"></a>' % { val: "sample.jpg"}
                                  # String#% 書式付文字列 ... (2)'' キーがシンボルなら
                                  # JSON.parse(jsonstring, symbolize_names: true) とか便利.
                                  # 名前が付けられるので自由度が高い.

'<a href="%<val>s %<n>04d.jpg"></a>' % {val: "sample", n: 1}   
                                  #                       ... (2)''' 置換と書式指定を同時にできる


(2)'' がいいのではなかろうかと.

Rubyで埋め込みシェルスクリプティングjcat

シェルスクリプトは強力である.しかし,痒いところに手が届かない.まとめて処理しようと思ったらプロセス数上限に到達したりとか.OSにとってプロセスの生成コストは高いのである.

そこで,Rubyシェルスクリプトのラッピングを施す.
具体的には,個別に完全なJSON文字列が入っているファイルを結合して一つのJSON文字列にする,名付けてjcat!

% cat A.json B.json
{"key1": valueA}
{"key2": valueB}

いや,次のようになってほしい.

puts jcat "A.json" "B.json"
{"key1": valueA,
 "key2": valueB}

実装は以下の通り.

require 'json'

def jcat(*args)
  return args.inject({}) {|acc, json|
  acc.merge(JSON.parse(File.open(json, "r:utf-8").read))
  }
end

JavaScriptで文字列書式付き出力

JavaScriptには,書式付きで文字列を生成してくれる関数がない.CでいうsprintfやJavaでいうformatのようなもの.これがないせいで,HTMLのマークアップ文字列に値を埋め込むのがめんどくさいこと限りなし.

ということで,Stringクラスを拡張.

if (!String.prototype.escape) {
    String.prototype.escape = function (o) {
        return this.replace(/{([^{}]*)}/g,
            function (a, b) {
                var r = o[b];
                return typeof r === 'string' || typeof r === 'number' ? r : a;
            }
        );
    };
}

文字列中に{key}があれば,引数の連想配列{key:value}によって,valueに置換される.
また,{0}等の数値であるばあい,可変の引数の順番にそれに置き換わる.

C#でJSON

C#JSONを扱うには,幾つか選択肢があるようだ.

のサマリです.

そもそも大本のJSON仕様はhttp://www.json.org/で.

.NET Framework 3.5 から

System.Service.Modelを参照に追加しよう.

.NET Framework 4.0 から

.NET Framework
  • System.Web.helpers
  • System.Web.Extentions.dll
    • JavaScriptSerializer

Win8 からのストアアプリなら.

このWindows.Data.Jsonは,よく検討された仕様にみえますね.でもどうやってWindows7+VS2013で使えばいいのかわからない...

日報ファイルをリネームしているのでござるよ,手動で.だから自動化.

  1. コピー
  2. F2
  3. 前日の日付を付与
  4. 保存

していたので,xyzzyでさくっとは行かないまでも,revision-up.2.5hもかかってしまった.

単なる保存がC-x C-wなので,C-x wに割り当て.ファイル名の先頭に前日日付を挿入します.

; C-x wに割り当て
(global-set-key '(#\C-x #\w) 'revision-up)

(defun revision-up (initial)
  (interactive "sNew Filename: " :default0
    (substitute-string (get-buffer-file-name)
                   "\\(.*\\)/\\(.*\\)"
		       (concat "\\1/" (format-date-string "%Y%m%d" (- (get-universal-time) 86400))"_\\2")))
  (write-file initial))

以下,解説

 (interactive "sNew Filename: " :default0 x)
;文字列を入力値として,ミニバッファにNew Filename: をプロンプトとして出力
;入力値の初期値はxで,最終的な値は本関数revision-upの最初の引数(:defalut0)であるinitialに代入される

 (format-date-string "%Y%m%d" (- (get-universal-time) 86400))
; 前日(86400秒前の年月日)の文字列を取得

    (substitute-string (get-buffer-file-name) "\\(.*\\)/\\(.*\\)" (concat "\\1/" yesterday "_\\2")
; 現在のフルパスファイル名から,パス名とファイル名にぶったぎって,前日日付を挿入して置換

以上です.

LISPって関数探しにくいわ.

理想の静的型付き言語(3)

 Swiftとの対比で、Haskellの文法を改めて見直してみた。Swiftは手続き的言語で予約語が多い。そういう意味ではPascal流のAdaや、直接の祖先であるC++の影響が色濃く残っている。こういう手続き型言語は文法が複雑になりがちなのでコンパイラを作るのに手間がかかる。その意味では関数型言語は文法が簡単になりやすい。Haskell関数型言語らしい、なんとかそのあたりを合体できないものだろうか。

 この点、Swiftでの構造体structのアプローチが注目するところだと思う。structはclassではないがclassのイニシャライザの形式で初期化できる。そして、実は、構造体識別子がなくてもコンパイルエラーにならないのだった。いわば、動的に構造体を定義できることになるのではなかろうか。

struct SomeStruct {
  var member1: Int
  var member2: String
}


var aStruct: SomeStruct = SomeStruct(member1: 0, member2: "test")              // 文法通り。

var another = (member1: 0, member2: "test")          // これもコンパイルが通る!

println(another.member1) // 0
println(another.member2) // "test"         

 この場合、括弧を関数引数とみるのではなく、タプル、と見ると、確かにタプルは異なる型を列挙できるデータ構造である。クロージャも引数のうちなので、タプルというデータ構造があれば、structもclassも同じ表記ができることになる。してみれば、structやclassというキーワードはシンタックスシュガーで、なくてもよいのではないか。LISPぽく表現してみると,,,

(defun SomeStruct (member1 member2)
  (list member1 member2))

(defvar another (SomeStruct 0 "test")) ;; (1)
; あるいは
(defvar another ((lambda (member1 member2) (list member1 member2) 0 "test")) ;;(2)

(1)(2) は同じものである。構造体は、単に順序対に名前を付けているだけということがわかる。