点字が拓く新しい世界

投稿者 nanki 2013-04-15 16:55:00 GMT

特に理由もなく一年以上放置していましたが、特に理由もなく再開します。

最近、仮想端末をiTerm2にしたので、xterm-256使えるぞと思って色々遊んでいました。(*OSX標準のターミナルもいつの間にかxterm-256対応していた)

Unicodeには点字を表現するための文字群があり、2x3の点字64種類とそれを含む2x4の点字256種類で構成されています。 これはUnicode中で自由に制御できる最も解像度の高い文字群ではないかと思い、xterm-256と合わせて利用してみることにしました。

# ちなみにこんなのです
⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿

Step 1

まずは点字のみで、二値画像を表現してみます。 ちょうど新しい職場でPythonを使い始める時期だったのでPythonで、二値画像としては手頃なマンデルブロ集合を使います。

ポイントはWikipediaにもありますが、2x3の点字が最初のほうに固まっているので、ビットを入れ替える必要があるところとマンデルブロの綴りくらいでしょうか。

mandelbrot

Step 2

Pythonにも慣れてきたので次はいよいよxterm-256を使いますが、いきなりカラーは難しそうなのでグレイスケールを使います。

The 256 color mode of xtermによれば、xterm-256はシステムカラー16色、6階調RGBの216色、グレイスケール24段階の計256色で構成されており、 以下のシーケンスで前景色、背景色が指定できます。(ここだけRubyです)

print "\e[38;5;#{color}m" # 前景色
print "\e[48;5;#{color}m" # 背景色
# グラデーションがでます
$ ruby -e '24.times{|i|print"\e[48;5;#{232+i}m "};puts'

そうしてできあがったのが以下のコードです。

基本的には、切り出された2x4pixelsに対して最も暗い色と明るい色を前景色/背景色に選び、各pixelをどちらかに振り分けるだけなんですが、

  • 誤差拡散法
  • なるべく前景色/背景色が同じにならないようにする
  • ガンマ調整(のようなもの)

といった工夫によりかなり画質を向上させています。 興味のある方はコードを弄って、どれくらい画質に影響を与えているか見てみると楽しいかもしれません。

lena

Step 3

カラー対応といいたい所ですが、3次元から1次元へ削減を行わないといけなかったり、人間の色覚モデルを考慮するのが面倒そうだったりしてまだやってないです。


白黒にするブックマークレット

投稿者 nanki 2012-01-19 02:21:00 GMT

Webkitの新しい奴で。


関西闇Ruby会議とFFI::Ruby

投稿者 nanki 2011-11-15 14:12:00 GMT

関西闇Ruby会議で発表しました。

内容は最近使う機会の増えたruby-ffi(フィッフィ)の紹介。 その時のスライドです。

ちょっとまとめきれなくて最後のほうにごちゃごちゃと書いてしまっていますが、C/Ruby間で独自の型変換を作れるとあったので試しにVALUE型をRubyのオブジェクトに変換するffi-rubyというのを作ってみました。 実用的なかおりがするけどあんまり使い途ない。

VALUE型の変換これであってるのかなぁ。簡単な恒等性のテストにはパスしてるみたいだけど。


Mac OS X でFrama-Cを使ってRubyを静的解析するメモ

投稿者 nanki 2011-11-06 18:11:00 GMT

@ikegami__さんのFrama-Cを使った実験が面白そうなので試してみた。

試験環境はMacBookAir/Mac OS X Lion/ruby192

インストール

$ brew install ocaml
$ wget http://frama-c.com/download/frama-c-Nitrogen-20111001.tar.gz
$ tar zxf frama-c-Nitrogen-20111001.tar.gz
$ cd frama-c-Nitrogen-20111001
$ ./configure --prefix=...
$ make
$ make install

使ってみる

Rubyのソースツリーに移動する。

$ cd ruby
$ ./configure

記事を参考に、.ext/include/ARCH_NAME/ruby/config.h に以下の行を追加。

#ifndef TRUE
  #define TRUE 1
#endif
#ifndef FALSE
  #define FALSE 0
#endif

解析対象ファイルの一覧を作っておく。

$ vi mainobj
array.c bignum.c class.c compar.c complex.c dir.c dln_find.c enum.c enumerator.c error.c eval.c load.c proc.c file.c gc.c hash.c inits.c io.c marshal.c math.c node.c numeric.c object.c pack.c parse.c process.c random.c range.c rational.c re.c regcomp.c regenc.c regerror.c regexec.c regparse.c regsyntax.c ruby.c safe.c signal.c sprintf.c st.c strftime.c string.c struct.c time.c transcode.c util.c variable.c compile.c debug.c iseq.c vm.c vm_dump.c thread.c cont.c

一覧は、common.mk中のCOMMONOBJSを参考にしている。

Frama-C Nitrogen 20111001 で ruby-1.9.2-p290 を検査するときにどうにもならなさそうな事であげられているファイルのいくつかは、直接コンパイルされることを想定して書かれていないので失敗するようだ。

解析開始

$ frama-c \
  -cpp-extra-args="-U__BLOCKS__ -DRUBY_EXPORT -I./.ext/include/ARCH_NAME -Iinclude" \
  -machdep x86_64 \
  -save ruby.session \
  `cat mainobj` 

-U__BLOCKS__はSnowLeopardから導入されたBlocks(Cの文法を拡張している)を無効にするため。これを無効にしないとparseが失敗する。

-machdep x86_64はARCH_NAMEにあわせたものを$ frama-c -machdep helpの結果から選ぶ。

$ frame-c -load ruby.session -metrics
...(ry)...
[metrics] Syntactic metrics
          -----------------
          ** Defined functions (6297):
          ...(ry)...

          ** Undefined functions (297):
          ...(ry)...

          ** Potential entry points (1694):
          ...(ry)...

          SLOC: 144947
          Number of if statements: 25635
          Number of assignments: 40691
          Number of loops: 3651
          Number of calls: 31176
          Number of gotos: 7496
          Number of pointer access: 50736

$ frame-c -load ruby.session -users -main rb_ary_new
...(ry)...
[users] ====== DISPLAYING USERS ======
        ary_alloc: rb_newobj
        ary_new: rb_newobj ary_alloc
        rb_ary_new2: rb_newobj ary_alloc ary_new
        rb_ary_new: rb_newobj rb_ary_new2 ary_alloc ary_new
        ====== END OF USERS ==========
参考:

CHM viewer on terminal

投稿者 nanki 2011-09-04 05:31:00 GMT

MacBookPro壊れてLinux使ってた時にGUIのものしか見当たらなかったので。

名前も未定です。

Rubyリファレンスマニュアルのchmは文字コード変なので悲しい。


Guardを使ったCoffeeScript開発

投稿者 nanki 2011-05-10 16:29:00 GMT

guardはファイルの変更を検知して、決められたタスクを実行するためのツールである。 Mac OS X / Linux / Windows それぞれのファイルシステム変更検知APIに対応しており、それ以外のプラットフォームではポーリングにて変更検知を行う。

$ gem install rb-fsevent # Mac OS X の場合
$ gem install guard
$ gem install guard-coffeescript
$ guard init coffeescript
$ vi Guardfile
guard 'coffeescript', :input => 'src/', :output => 'dist/'
$ guard start

こうすることで、src/ 以下の.coffeeファイルに変更があった場合即座にコンパイルされ、dist/以下に.jsファイルが生成される。

なお、rb-fseventは入れなくても動くがその場合はポーリングになる。 Mac以外のOSではこうするらしい。

$ gem install rb-inotify # Linuxの場合
$ gem install rb-fchange # Windowsの場合

guard-coffeescriptの他にも様々なguardがあるようです。

参考:

猫も杓子もCoffeeScriptの世の中、CoffeeScriptに手を出してしまったがために(JavaScriptの世に)帰らぬ人となりつつある人はたくさんいると思う。 僕も最近CoffeeScriptに手を染め五分で帰り途を見失ってしまった。

CoffeeScriptの編集にはujihisa氏のshadow.vimが便利だ。 shadow.vimを手短に紹介すると、main.js を開いて編集していると思ったら実はmain.js.shd(中身はCoffeeScript)を編集していて、気づいた時にはすでにmain.js.shdのコンパイル結果がmain.jsに保存されている、というvim-pluginである。

さて、JavaScriptを本格的に使うには、モジュールシステムを避けて通る事はできない。 グローバル変数を多用することも許されているJavaScriptでは、ライブラリによるオブジェクト空間の汚染は予測できない結果を引き起こしかねない。

モジュールシステムは未だ黎明期なので、本稿ではベストのものを選択するよりは、CoffeeScriptで書くクライアントサイド(以下CS)コードをサーバサイド(以下SS)でテストすることを念頭に、モジュールシステムの選び方を検討する、という方向で行こうと思う。 なお、ブラウザによる互換性は面倒くさいのでチェックしない。どうせやってることは一緒なのでいざとなれば解決可能な問題だし、各自で使用前にチェックしてください。

CommonJS

JavaScriptの処理系はちょっとリストアップするのが大変なほどある。

これらでばらばらのライブラリAPIを使われてはたまらないので、標準を決めようという事で、CommonJSと呼ばれる標準のようなものがあるらしい。 CS-APIではまだ存在する実装をまとめただけのような雰囲気もあり、CommonJS準拠だから選ぶ、ということにはならないが、 ありがたいことに、CommonJSに参加?しているプロジェクト一覧があり、これをベースに見ていくと楽できそうだ。

リストのうち、ブラウザ向けのものは

以下はリストには載ってないが見つけたやつ。

モジュールシステムについては、Modulesに関係する仕様と提案があり、これを参考にする。

Modules

おおまかに言うと、Modules/1.0では以下のようなrequireexports変数を使ったオブジェクトのエクスポートを要求している。

    // math.js
    exports.add = function(x, y) { return x + y }

    // increment.js
    var add = require('math').add
    exports.increment = function(val) {
      return add(val, 1)
    }

    // main.js
    require('increment').increment(2) //=> 3

SSの処理系ではこれは広くサポートされているようだ。

Modules/AsynchronousDefinition (AMD)

CSでは、スクリプトの読み込み方法が限られている(scriptタグの追加かXHRによる読み込み)し、同期的読み込みを前提とした上記のような定義方法は実用的ではない。 そこでModules/Transport/* という名前でいくつかの提案がされている。

歴史的な経緯はよくわからないが、Modules/Transport/Aの実装であったRunJSはModules/Transport/Cの実装であるRequireJSへと名前を変え、 Modules/Transport/CModules/AsynchronousDefinition(以下AMD)へと昇格?しているらしい。 AMDは以下のような形式で、他のものと比べて暗黙的な変数の導入がなく、スジがよいように思える。 これがデファクトになっていくのだろうか。

    // define(moduleId?, deps?, factory function / object to be exported)

    // math.js
    define({
      add: function(x, y) { return x + y }
    })

    // increment.js
    define('increment', ['math'], function(math) {
      return {
        increment: function(val) {
          return math.add(val, 1)
        }
      }
    })

CoffeeScriptとの相性もよい。これは今回は重要なポイントだ。参考までにCoffeeScript版も書いておく。

    // increment.coffee
    define ['math'], (math) ->
      increment: (val) -> math.add(val, 1)

Modules/1.xとの互換性を考慮した

    // increment.js
    define('increment', ['math', 'require', 'exports'], function(math, require, exports) {
      // これより内側がModules/1.xの定義そのままで動く
      exports.increment = function(val) {
        return require('math').add(val, 1)
      }
    })

といった書き方も用意されているようだ。

採用しているライブラリは

など。

Modules/Wrappings

    //increment.js
    module.declare(['math'], function(require, exports, module) {
      return {
        increment: function(val) {
          return require('math').add(val, 1)
        }
      }
    })

あんまり違いがわからないが、ポイントはfactory関数の引数がrequire, exports, moduleの三つで固定されていることだろうか。その名前から、Modules/1.xとの互換性目的のものと思われる。 exportsを使ってもよいし、factory関数の返り値としてオブジェクトを返せばそれがそのままモジュールになる。

Modules/Async/A

AMDに対応したローダーの仕様はModules/Async/Aに書かれている。 といっても、Yabbleの実装(下記)をそのまま書いてあるだけのような気がするが。 対応ライブラリはYabbleのみしか書かれていない…え…

結局のところ、AMDはdefineの文法的形式が決まっているだけで、ローダにはまだ決定打がない。 コードを書く際はローダの呼び出しを最小限にするのが良さそうだ。

この辺がCommonJSの限界のようなので、あとは各々の実装を見ていくのがよさそうだ。

Yabble

    // increment.js
    require.define({
      increment: function(require, exports, module) {
        var math = require('math')
        exports.increment = function(val) {
          return math.add(val, 1)
        }
      }
    }, ['math'])

    // main.js
    require.ensure(['increment'], function(require) {
      require('increment').increment(2); // 3
    });

第一引数に依存するモジュールを、第二引数にcallbackを指定する。モジュールのロードが完了すると、callbackが呼ばれる。

テストコードも豊富でなかなか完成度の高いコードだ。 しかし、SSで使われることは想定されておらず、本体に手を入れずに使うことはできなさそう。 SSのテストコードでは利用する機能を搾って、同じインターフェースを持つ他のライブラリに丸投げする事が可能だ。 (例えばNodulesは、require.ensureを持っている)

Nodules

    //main.js
    require.ensure(['increment'], function(require) {
      require('increment').increment(2); // 3
    });
$ node PATH_TO_NODULES/lib/nodules.js main.js

こんな感じで。

Nodulesの機能のこれはごく一部で、この他に

  • HTTP上のjsをrequireする(そのためのrequire.ensure)
  • Packages/Mappingsの実装

など。

コマンドラインからの起動が必要なのはマイナスポイント。 あと、defineの第一引数を指定すると、ファイル名(フルパス)と違うと怒られた。

RequireJS

同じものがRequireJSではこうだ。

    require(['increment'], function(increment) {
      increment(2); // 3
    });

シンプルすぎて泣ける。かっこいい。 なお、defineは、一つのファイルに複数のモジュールを記述することを許しているがその場合は、

    //libs.js
    define('math', {  })
    define('increment', ['math'], {  })

    //main.js
    require(['require', 'libs'], function(require) {
      require('math').increment(2); // 3
    });

というように多段にしてrequireすればよい。

RequireJSはSSでの(node, rhinoに対応)実行も行えるようになっており、

$ PATH_TO_REQUIREJS/bin/x main.js

とすればいい。この時、engine-nativeのrequire関数はオーバロードされる。 ただこの方法だと、CoffeeScript中のrequireなどは置き換えられないため若干使いづらいし、そもそもrequireを汚染されるのは気持ちのいい物ではない。

これに関しては、wrapperを書く事で、通常のライブラリと同様読み込むことができるようだ。

    // requirejs-node.js
    (function() {
      var read = require('fs').readFileSync
      var run = require('vm').runInNewContext

      var env = {
        importScripts: function(url) {
          run(read(url), env)
        }
      }

      var code = read(require.resolve('require'))
      run(code, env)

      exports.require = env.require
      exports.define = env.define
    }).call()

    // main.coffee
    rjs = require 'requirejs-node'
    rjs.require ['your_library'], (library) -> ...

rjs.requireで読み込まれるライブラリ内ではrequire = rjs.require, define = rjs.define となる。

Dojo

Dojoでは1.6以降AMD形式のライブラリを提供していく予定らしい。 Loaderは提供しないので、今回は関係ない。

LoaderにはbdLoad / RequireJS を使えとのこと。

backdraft / bdLoad

backdraft frameworkの中のbdLoadというのがそれらしい。

のが売りだそうだ。

RequireJSのテストコードがレポジトリに含まれていることから、RequireJSのよりよい実装と考えてもよさそうだ。

NodeJS用のインターフェースもデフォルトで用意されている。

上記RequireJSではwrapperを書いたが、bdLoadではデフォルトでほぼ同じ様になる。

    // bdload-node.coffee
    bdLoad = require('node').boot()

    bdLoad.require
      paths:
        mylib: './mylib/lib'

    bdLoad.require ['mylib/mylib'], (mylib) -> ...

これはかなりいい。RequireJSを選ぶ理由はほぼない気がする。RequireJSはリファレンスマニュアルがかっこいい。

ちなみに、backdraftレポジトリをcloneしようとしたら、AAを用いたCAPTCHAのようなものが表示され、フォントが違うので読めなくてログインできない。CAPTCHAは見る価値あり。

OzJS

作者(dexteryy)はtudou.comのフロントエンジニアらしい。 スライドは中国語で詳しくはわからないが、かなり詳細に論じている様子が伺える。 他のライブラリに比べると圧倒的にサイズが小さいし、TUICompilerというのを使って静的に複数のスクリプトをまとめることができるようだ。

ただし、NodeJSからは使えなかった。 あとoz.defという名前で微妙にAMDと互換性がないので、気にする人はdefine = oz.defしてそっちを使うのがよいかもしれない。

    // increment.js
    var define = oz.def
    oz.def('math', 'math.js')

    define('increment', ['math'], function(math) {
      return {
        increment: function(val) {
          return math.add(val, 1)
        }
      }
    })

    // main.js
    oz.require(['increment'], function(increment) {
      increment.increment(2) //=> 3
    })

FlyScript

Modules/Wrappingsを採用しているFlyScriptだが、何があったのかgithubのレポジトリが消えている。 作者の他のレポジトリも丸々ないので公開やめたのかな…

SeaJS

Modules/Wrappingsなのでこんな感じ。

    //increment.js
    define(['math'], function(require, exports, module) {
      return {
        increment: function(val) {
          return require('math').add(val, 1)
        }
      }
    })

    //main.js
    seajs.config({
      base: './...',
      alias: {
        //...
      }
    })

    seajs.use(['increment'], function(increment) {
      increment.increment(2) //=> 3
    })

SSでは動かなかった。 Backbone.js系のライブラリを添付してくれていて助かるが、必ずmoduleId.jsを読みに行ってしまうみたい。 これは、production環境でファイルをまとめたい時などには困るだろう。 お手軽にBackbone.jsで遊ぶ専用か。

JSLocalnet

  • ライセンスがGPLv3/プロプライエタリ
  • XHRにしか対応してない
  • IE8非対応
  • コメントがスペイン語
  • レポジトリがhg
  • テストコード一切無し

と、異なる文化圏にあるようでちゃんと見るのやめました。

PINF JS Loader / bravojs

Modules/2.0!

Modules/Wrappingsとの違いがよく分からない…

未実装の部分が多いが、完成するとかなりの処理系(JetPack, NodeJS, browsers…) にまたがって共通のモジュールシステムを提供することになるようだ。 Modules/2.0提案用のリファレンス実装という色が濃く、unstable感が高いので今回はパス。

curl.js - updated on 2010/05/05

curl.jscujo platform用のAMDローダ。 以前まではdojoのローダを使っていたようだが、今はAMDを使うようになったamdブランチがあるようだ。 まだリリースされて一ヶ月とあまり情報もないので見逃していた。 SSでは動かない。

  • 素直にAMDを実装
  • next, thenなど独自機能
  • ‘text!xxxx.text’ でテキストファイルをロード
  • ‘js!xxxx.js’ でnon-AMDなjsをロード

といった感じ。特に最後の拡張は、AMD非対応jsが多い現状を考えると面白い。

作者のスライド(オススメ)によれば、AMDではrequireはThe Wild Westだという。 しかし、requireの呼び出しはコードの1%にも満たないので、もっとやれ!ということのようだ。

    curl({
      baseUrl: '...',
      paths: ['.']
    }, {})

    require(['increment'], function(increment) {
      increment.increment(2); // 3
    });

    // 別の書き方
    require(['increment'], (function(increment) {
      increment.increment(2); // 3
    })
    .next(['js!jquery.js!order', 'js!zoom.js!order'])
    .then(function() {/* success */}, function(e) {/* error */});

サイズ

CSで利用する際に気になるのはサイズだが各ライブラリの主要ファイルのサイズを以下の方法で調べた。

$ uglifyjs -nc --unsafe < xxx.js | wc -c
$ uglifyjs -nc --unsafe < xxx.js | gzip -c | wc -c

OzJSがもっとも小さく、RequireJSが最も大きいがその差は数倍程度の開きでしかなく、あまり大きな要素にはならないように感じた。 まとめの項に表を示す。

まとめ

CSのモジュール定義はAMDでほぼ確定、ローダは標準なしということで、 様々なモジュールローダを見て来たが、SS/CSで動くよう作られたライブラリはやはり少なかった。 現時点では、SS/CSで使うライブラリをわけるのが選択の幅を狭めない妥協点だ。

| library    | license             | server-side | size  | gziped | nank  |
| RequireJS  | MIT / mBSD          | ?           | 16486 | 5788   | ★★★☆☆ |
| bdLoad     | BSD                 | o           | 11221 | 4714   | ★★★★★ |
| OzJS       | MIT                 | x           | 3143  | 1543   | ★★★★☆ |
| SeaJS      | MIT                 | x           | 5489  | 2319   | ★★☆☆☆ |
| Yabble     | MIT                 | x           | 6635  | 2468   | ★★★★☆ |
| bravojs    | MIT                 | o           | 8646  | 2671   | ★★★☆☆ |
| curl.js    | MIT                 | x           | 4627  | 2247   | ★★★★☆ |
| JSLocalnet | GPLv3 / Proprietary | x           | -     | -      | -     |
| FlyScript  | MIT                 | -           | 8594  | 3831   | -     |
| Nodules    | mBSD / AFL2.1       | o           | -     | -      | -     |

PINF JS Loader / bravojs の組み合わせは今回の様な用途を本気で目指したものであり、今後注視しておきたいが、今変化の直中であり手を出しづらい。

また、中国製のライブラリがいくつか(OzJS, SeaJS)見受けられ、中国でJavaScriptがキてるのが感じられる。 この組み合わせは強そうだ。

バランスがいいと感じたのはbdLoadであったが、さらに踏み込んで使いたい場合はOzJS / curl.js もよい選択だと思う。

おまけ

名前が挙ってたので調べたけど、関係なさそうなやつ。

Teleport

teleportは、browserでの開発にNodeJSのエコシステムを持ち込むものらしい。

$ npm init # package.json作成
$ npm link
$ vi index.html
$ teleport activate

とすることで、開発中のpackageにhttp://localhost:4747/PACKAGE_NAME/でアクセスできるようになる。 http://localhost:4747/teleport-dashboard/でnpm管理下のパッケージ一覧が見られる。 browser上でrequire('...')などとすると、npmパッケージをロードすることができる。

この時、Modules/1.x 形式のモジュールを、defineでくるんでCSに送信する。

また、require/define がすでに定義されている場合は、上書きしないような配慮がされている。 うまく開発プロセスに組み込めば、ブラウザによるテストも楽になりそう。

リリース時には、$ teleport bundle PACKAGE_NAME/app とすることで、必要なパッケージを展開?してくれるようだが、これはバグで動かなかった。

Transporter

Transporterでは、Modules/1.0モジュールを、様々なtransport形式でCSに提供するSSの仕組みを提供している。 CS-APIは、require.ensure / defineを使うようだが、非同期読み込みには対応しておらず、自分であらかじめscriptタグで読み込んでおく必要があるようだ。 利点がわからない…誰か教えて…

参考:

iPhoneアプリPhotosynthで鴨川デルタを撮影

投稿者 nanki 2011-04-20 10:14:00 GMT

こういうエントリはほとんど書かないんだけど、Photosynthはそのはじめのころからずっと見ていたし、首の消えてしまったおじさん(プライバシーに配慮して)の向うには出町ミスドがあるし、なによりPhotosynthが素晴らしかったので。

iPhone持ってる人は一度は試してみるべき。共有しなければアカウント作成とか要らない。

一部破綻が見られるけど、iPhoneで誰でも撮れるというのはかなりインパクト大きい。 bing map今からでもGoogleMapsと張り合える。

しかし相変わらず弱そうなソーシャルパートw 外部にライセンスするか、api公開していい会社買った方がいいものできそう。


Mac OS X で変な漢字を探す亖つの方法

投稿者 nanki 2011-04-20 07:05:00 GMT

元々の話題は、火が三つの漢字を見た事あるけど見つからない、というものから。

1. 手書き文字入力 / ⌃⌥ Space / Ctrl+Shift+Space

手書き文字入力

詳しくは下記URLの記事を参照。

2. ⌃1, ⌃2 / Ctrl+1, Ctrl+2

部品の共通な漢字を検索 対象となる文字を選択後、Ctrl+1を押す

関連文字に変換 対象となる文字を選択後、Ctrl+2を押す

3. 文字ビューア

「文字ビューアを表示」を選択

記号など探すには便利。地道に探す。 文字ビューア

4. CHISE/漢字構造情報データベースを使う

CHISE IDS Findを使って検索するか、CHISEプロジェクトからデータベースをダウンロードして自分で探す。

今回のように三つの文字が並んでいる漢字を探す場合、例えば”森”、という字なら、

… 森 ⿱木⿰木木

という感じの表現で入っているはずなので、UTF-8を正しく扱えるシステム上で /\t⿱(.)⿰\1\1$/ という正規表現を使えば、同じ漢字が三つ並んだ漢字の一覧を得ることができる。 上記は簡単だが手抜きなやり方で、完全性に関してはいくつか問題がある。

  1. 文字に対する表現の曖昧性 例えば、森に対しては⿱木林 / ⿱木⿰木木の二つの表現が考えられる。検索時にこれを考慮しなくてはならない。(同じ漢字が四つならぶ時など考えたくない…)

  2. 包摂の扱い 同じ漢字なんだけど字形が違う場合、例えば「」の各部品はトメ、ハライの違いを考慮してデータベースに登録されており、上記のような単純な正規表現ではこれは扱う事ができない。

というわけで、今回見つけられた同じ漢字が三つの文字(ただしSnowLeopardで表示されるものに限る)は

post先のサーバがどれかの文字を正しく扱う事ができず途中で切れてしまったので画像で失礼。

参考:

ObjectSpaceダンプ

投稿者 nanki 2011-02-17 14:03:00 GMT
def top_objects(num=20)
  ObjectSpace.each_object.inject(Hash.new{0}){|h,o|h[o.class]+=1;h}.sort_by{|k,v|-v}.first(num).each{|k,v|puts "#{k}\t#{v}"}
end

GC.start
top_objects

--
String  577159
Array  163891
Hash  93468
Time  50353
ActiveSupport::TimeWithZone  50129
ActiveModel::Errors  23365
TZInfo::TimezonePeriod  23340
ActiveSupport::HashWithIndifferentAccess  23236
RubyVM::InstructionSequence  12484
MIME::Type  1197
MatchData  1183
ActiveModel::AttributeMethods::ClassMethods::AttributeMethodMatcher::AttributeMethodMatch  1128
Class  1101
Regexp  972
Proc  704
Module  655
Gem::Version  619

GCを生き残ったインスタンス数をダンプ。