2014/08/22


誰も作ってくれないので自分で作った。

mattn/ujihisa - GitHub
https://github.com/mattn/ujihisa

golang で書かれています。go get github.com/mattn/ujihisa/ujm でインストール出来ます。使い方は

$ ujm [filename]

です。ファイル名が無い場合は標準入力から読み取ります。ベースは whitespace です。スペース文字が 便利、タブ文字が 感極まってきました に置き換わります。whitespace に慣れている人ならスイスイと書けるかと思います。例えば

便利便利便利感極まってきました
感極まってきました
便利感極まってきました



この様なコードなら 1 という数字が出力されます。

なお、便利 という文字を出力するにはこれくらいのコードが必要になります。golang で書かれているので Windows でも動きますし、文字の表示でユニコードを使うと Windows でも問題なく表示されます。

とても便利だと思うので、ぜひ使ってみて下さい。


2014/07/31


ShellScript - jq、xmllintコマンドさようなら。俺はパイプが好きだから - Qiita

UNIX哲学の一つとしてよく引用されるマイク・ガンカーズの教義に

  • 1.小さいものは美しい。
  • 2.1つのプログラムには1つのことをうまくやらせよ。

というのがあるが、まずこれができていない

http://qiita.com/richmikan@github/items/e051b5d882c3dd2a39c6

昔の UNIX で扱っていたデータはだいたい行指向でした。そして UNIX は行指向データを扱う為の OS と言っても過言ではありませんでした。 しかし JSON はどうでしょう。JSON は行指向ではありません。ならばツールを変えるのが正しい選択だと思いますし、そこでシェルを選ぶのは正直マニアの方しかいませんよね。 入力データがバイナリであれば、ツールも変えるはずです。JSON もそうすべきだと僕は思います。

理由1. 一つのことをうまくやっていない

ShellScript - jq、xmllintコマンドさようなら。俺はパイプが好きだから - Qiita

JSON だけを扱っていますすし、他のデータを扱ってはいないですよね。

理由2. フィルターとして振る舞うようになりきれてない

ShellScript - jq、xmllintコマンドさようなら。俺はパイプが好きだから - Qiita

jq は JSON の grep 的な存在だと思っています。僕は jq を使いこなしている訳ではないし、「便利だなー」くらいにしか思っていませんが、JSON をシェルで扱いたいと思った場合にはJSON が苦無く扱える言語やツールを選びます

ちなみに jq だと上記の問題はどの様に解決出来るか試してみました。

#!/bin/bash

FILE=$1
cat $FILE | jq -r 'paths|map(if type=="number" then "["+tostring+"]" else "["+tojson+"]" end)|join("")' |\
while read line; do
    value=`cat $FILE | jq -r ".$line|if type==\"string\" or type==\"number\" then \"MATCH:\"+tostring else empty end"`
    if [ "x$value" != "x" ]then
        echo $value sed "s/^MATCH:/.$line\t/"
    fi
done

実行結果は以下の通り。

.["会員名"] 文具 太郎
.["購入品"][0]  はさみ
.["購入品"][1]  ノート(A4,無地)
.["購入品"][2]  シャープペンシル
.["購入品"][3]["取寄商品"]  替え芯
.["購入品"][4]  クリアファイル
.["購入品"][5]["取寄商品"]  6穴パンチ

パスは jq のパス式です。短くていいですね。

ネタだったら、マジレスごめんなさい


2014/07/30


おなじみC/C++から使えるJSONライブラリを紹介するコーナー。まずは過去のまとめ。

今回は json11 というライブラリ。

dropbox/json11 - GitHub
https://github.com/dropbox/json11

あの Dropbox が書いてる。C++ から使える JSON ライブラリは幾つかありますが、initializer_list が使える物がなかなか少ない。

json11 は以下の様に書ける。

Json my_json = Json::object {
    { "key1""value1" },
    { "key2"false },
    { "key3", Json::array { 123 } },
};

前回の jansson の記事で使ったサンプルを json11 で書くと以下の様になります。

※ネットワーク通信部分は前回のコードよりも省略しています

C++11 向けライブラリですのでコンパイル時のコマンドラインオプションに -std=c++11 を付ける必要があります。

#include <iostream>
#include "json11.hpp"
#include <curl/curl.h>

size_t
stream_write(char* ptr, size_t size, size_t nmemb, void* stream) {
  ((std::string*) stream)->append(std::string(ptr, size * nmemb));
  return size * nmemb;
}

int
main() {
  CURL* curl;
  std::string buf;
  curl = curl_easy_init();
  curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/legacy/repos/search/unko");
  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
  curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl");
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf);
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, stream_write);
  curl_easy_perform(curl);
  curl_easy_cleanup(curl);

  std::string err;
  json11::Json v = json11::Json::parse(buf, err);
  for (auto &k : v["repositories"].array_items()) {
    std::cout << k["username"].string_value() << std::endl;
    std::cout << k["name"].string_value() << std::endl;
    std::cout << k["description"].string_value() << std::endl << std::endl;
  }
}

とてもきれい。ライセンスは MIT なので業務でも使えます。