Greple 仕様変更と多色化

関連


--cut やめて --need にしました

新しく --need というオプションを作って、マッチするパターンの数を指定できるようにしました。 そこで負の値を指定すると、今までの --cut と同じ意味になります。 --cut の方はわかりにくいので、まだ使っている人はいないだろうと思って削除しちゃいました。

ネガティブマッチを許す --allow の方はそのままで、やはり負の値を受け付けるようにしました。

greple --need=2 --allow=1 'foo bar baz -yabba -dabba -doo'

--print 関数の仕様変更

--print オプションで指定する関数の仕様を変えました。

今までは関数の返り値は見ていなかったのですが、今は返って来た値を出力するようになっています。 ですから、関数では出力したい文字列を返すようにします。 関数内で出力しちゃった場合には、空文字列を返してください。

また、--continue オプションを指定すると、返り値をそのまま出力せずに、通常の出力処理を続けるようになっています。 元の文字列を変更してしまうと、うまく出ないことがあるので注意して使いましょう。


多色化

--colormode で複数の色を指定できるようにしました。 そうすると、指定したキーワード毎に違う色を使うようになります。

また --colorful というオプションを追加して、これは --colormode 'RD GD BD CD MD YD' と同じ意味です。 このように出力されます。

f:id:uta46:20140113160441p:plain

こんな例だとあまり役に立つようには見えませんが、たとえばこんな風にするといくらか使い道はあるかもしれません。

greple --colorful --need 1 --icode=auto -e '\p{Han}+' -e '\p{InHiragana}+' -e '\p{InKatakana}+' -e '[a-zA-Z]+' -e '\d+' -e '[\pP\pS]+'

f:id:uta46:20140113160518p:plain

調子にのって --random というオプションも付けてみました。 ポップな感じですが、あまり意味はありません。

greple --all --colorful --random '\S+' greple

f:id:uta46:20140113160605p:plain

Greple で iCal データを検索する

追記: 申し訳ありませんが、--print で使用する関数の仕様を変更して、関数の返り値を出力するようにしました。 関数内で出力している場合は、空文字列を返すようにしてください。


--chdir, --glob オプション

OS X のカレンダーコマンドは iCalendar という形式でデータを管理していて、ファイルは ~/Library/Calendars というディレクトリの下に保存されている。

たとえば、こんな風にすれば iCal のデータを検索することはできる。

% cd ~/Library/Calendars
% grep PATTERN *.caldav/*.calendar/Events/*.ics

Greple--chdir--glob オプションを使うと、同じことがこんな風にできる。

% greple --chdir ~/Library/Calendars  --glob='*.caldav/*.calendar/Events/*.ics' PATTERN

複数のディレクトリを --chdir で指定することもできる。 その場合、それぞれのディレクトリに移動した後で --glob オプションを解釈する。

% greple --chdir '~/Library/Calendars/*.caldav/*.calendar/Events/' --glob '*.ics' PATTERN

憶えておくのは大変なので、alias を作ってもいいし、~/.greplerc ファイルに次のように書いておくと --ical_data という新しいオプションが有効になる。

% greple --ical_data PATTERN

これだと、マッチした行しか表示されないので日付とかがわからない。 iCal のデータは、1つのイベントを1つのファイルに保存しているので、ファイル全体を表示させるためには、--all というオプションを使う。

% greple --ical_data --all PATTERN

ここまでは grep-r オプションを使っても、大体同じことができる。 マニュアルには書いてないが、-C オプションに -1 を指定するとファイル全体を表示するようだ。 と思ったけど、-C オプションに負の数を指定した場合の挙動は不可解だ。

% grep -rhC-1 --include '*.ics' PATTERN *.caldav

--print オプション

greple--print オプションを使うと、出力用の関数を定義することができる。 もっとも簡単な使い方はこんな具合。

% greple --print='sub{$_}' PATTERN

値には Perl のサブルーチン名を指定するか、直接コーディングする。 マッチした領域は $_ 変数に入ってきて、関数の返り値が出力される。

iCal のデータを表示するためには、たとえば ~/.greplerc にこのような関数を定義する。

.greplrc definition to search iCal data and displa ...

こうして、次のように実行すると、iCal のデータを1行ずつ表示してくれる。 イベント名だけを検索したければ SUMMARY 行を指定する。 TODO などを除外して EVENT だけを検索したければ、VEVENT というフィールドも指定する。

% greple --ical PATTERN

% greple --ical '^SUMMARY.*PATTERN'

% greple --ical 'VEVENT ^SUMMARY.*PATTERN'

これだと、順番が出鱈目なので、日付順に表示したければ結果を sort する。 --of オプションで出力フィルタを指定することができるので、.greplerc の中に --of=sort を入れてしまっても構わない。 試しに、10年前の正月にどんな映画を観ていたかを検索してみるとこんな結果になった。 なるほど、とっとこハム太郎を観ていたのかw

% greple --ical '200401\d\d 映画' | sort
2003/01/02 14:00-15:00 映画:とっとこハム太郎 ハムハムハムージャ!幻のプリンセス
2003/01/02 15:00-16:30 映画:ゴジラ対メカゴジラ
2004/01/02 12:20-13:25 映画:劇場版 とっとこハム太郎ハムハムグランプリオーロラ谷の奇跡リボンちゃん危機一髪
2004/01/02 13:30-15:00 映画:ゴジラ×モスラ×メカゴジラ 東京SOS
2004/01/08 19:30-21:30 映画:ミシェル・ヴァイヨン@池袋HUMAX
2004/01/13 20:10-22:00 映画:ブルース・オールマイティ@サンシャイン
2004/01/16 20:40-22:55 映画:半落ち@サンシャイン
2004/01/21 22:00-00:00 映画:リクルート
2004/01/24 21:30-23:30 映画:タイムライン
2004/01/25 21:00-23:00 映画:首都消失@TV
2004/01/29 20:30-23:00 映画:ミスティック・リバー@新宿ジョイシネマ

おや、2003年のデータが混じってるな?と思ったら、こうやって中身を見ることができる。

% greple --ical_data --all ハムハムハムージャ!

すると、DTSTAMP というフィールドが2004年になっていることがわかった。 RFC2445 によれば、これはオブジェクトが作成された日付ということだ。

厳密に書くとすればこんな具合だろうか。 最初からきっちり書くのではなく、ゆるく初めて必要に応じて絞り込むような使い方がお勧めである。

% greple --ical '^BEGIN:VEVENT ^DTSTART.*200401\d\d ^SUMMARY.*映画' | sort

greple --strict オプション

先日の変更で、greple コマンドに --strict オプションが付いている。実際には、デフォルトの挙動を変更して、以前と同じ動作をさせるために strict モードを追加したことになる。

何がどう変わったか。greple には --inside, --outside, --block などのマッチする領域を制限するオプションがあるが、以前は指定したパターンが完全にこれらの領域に含まれている時だけマッチが成功した。現在は、パターンの一部でも領域に含まれていればマッチが成功するようになっている。

たとえば、

greple --inside and command

というパターンは、以前は決してマッチしなかったが、今はする。--outside にしても結果は同じだ。

これが役に立つケースというのをあまり思いつかないのではあるが、たとえば

greple -n --block='(.*\n){1,10}' -e 'Be aware' README.md

みたいに、10行ずつのブロックを検索した時に、パターンが複数ブロックにまたがっている場合でも発見することができる。 以前は、1つのマッチは1つのブロックにしか影響を与えることができなかったのだが、それが複数ブロックになったということだ。

固定長のレコードデータなんかは、隣のレコードと一緒になってマッチしては困るだろうから --strict オプションを使った方がいいだろう

greple --strict --block='(?s).{80}' ...

ハカイシをハックする

いろいろあって、墓石のデザインを考えることになった。経緯はすっとばして、結論として辿り着いたテーマは黄金比とスーパー楕円。黄金比は説明するまでもないだろう。ダビンチとかオウムガイのあれだ。と一言で片付けようと思ったが、え、オウムガイは違うのか?深入りすると長くなりそうなので保留。

f:id:uta46:20131126092725p:plain

楕円の公式は (x/n)2 + (y/m)2 = 1 だが、この2乗の部分が 2 より大きくなったものをスーパー楕円と呼ぶ。

f:id:uta46:20131127150611j:plain

Wolfram Alpha というサイトで、横 1.0 縦 1.6 の黄金比の3乗のスーパー楕円を描くとこのようになる。

f:id:uta46:20131126093145j:plain

必要なのは第一象限だけなので、そこの部分を何種類か表示してどれがいいかを考える。冪数は整数ではなくてもよい。

f:id:uta46:20131126093728p:plain

f:id:uta46:20140113161536p:plain

2.5 か 2.8 のどちらがいいか迷って、最終的には 2.8 を選択した。

業者さんに渡すための図形を描くのには gnuplot を使用。 方程式を解いて

y = 1.6 (1 - x 2.8) 1/2.8

を求めればいい。 第一象限だけを表示するプログラムはこんなものか。 初めて使ったので稚拙な部分があると思うがご勘弁を。

Golden Ratio Superellipse by Gnuplot

f:id:uta46:20131126094802p:plain

デザインには Google Sketchup を使用。曲線を描くのに Rubyプラグインを使おうかとも思ったが、プラグインRuby も未経験で時間がかかりそうだったので見送り。Perl で計算した座標を手作業で入力した。x を 0 から 1.0 まで変化させて求めるわけだが、1.0 に近くなるに従って細かくしないと線が荒くなってしまう。その辺は適当に調整したのだが、後から考えると角度を等分して cosign を求めた方がよかった。5度間隔で表示するとすれば、こんな具合になるだろう。今回は幅300mm、高さ480mmの楕円を描くので300倍している。

スーパー楕円の座標を計算する

x=0.000000, 0.000000, 480.000000
x=0.087156, 26.146723, 479.815046
x=0.173648, 52.094453, 478.722973
x=0.258819, 77.645714, 476.076512
x=0.342020, 102.606043, 471.360546
x=0.422618, 126.785479, 464.161505
x=0.500000, 150.000000, 454.150177
x=0.573576, 172.072931, 441.067116
x=0.642788, 192.836283, 424.708888
x=0.707107, 212.132034, 404.914265
x=0.766044, 229.813333, 381.549201
x=0.819152, 245.745613, 354.488587
x=0.866025, 259.807621, 323.591140
x=0.906308, 271.892336, 288.659917
x=0.939693, 281.907786, 249.371266
x=0.965926, 289.777748, 205.125829
x=0.984808, 295.442326, 154.665394
x=0.996195, 298.858409, 94.680866
x=1.000000, 300.000000, 0.000000

結果として、このようなものができあがった。細かい部分は石材屋さんが細工するので、この通りに仕上がるわけではない。花立や香炉の穴の部分もスーパー楕円だ。石塔の部分が奥行き1尺、高さ1尺6寸の黄金比。幅は2尺ということだったが、頑張って2尺5寸とってくれることになったので、正面もほぼ黄金比で出来上がることになった。石材屋さんとしてはもう少し高くしたいらしいが、せっかくなのでこのままで行くことに。

f:id:uta46:20131125223642j:plain

テクスチャを貼るともっとそれらしいのだが、モノがモノだけになんか生々しいのでワイヤーフレームです。さて、どうなりますでしょうか。

greple command released

先月 mg というコマンドを Unicode 対応しましたが、その後全面的に見直してオプション体系も新しくなったので、greple という名前に変更してリリースすることにしました。

ドキュメントを git に合わせて markdown で書いたら、それは hatenablog でしか使えないようなので、ついでにブログも移行してみた。

使用例は今後も更新するので、最新版はこちらをどうぞ

Greple Examples


Keywords / キーワード

find multiple words all / 全部ある行を表示する

greple 'foo bar baz'
greple -e foo -e bar -e baz

x foo baz
o foo bar baz
o baz, bar and foo

negative match / 除外したい単語を指定する

greple 'foo bar baz -yabba -dabba -doo'
greple -e foo -e bar -e baz -v yabba -v dabba -v doo

x foo bar
o baz bar foo
x foo bar baz doo

alternative match / どれかひとつあればいいんだけど

greple 'foo bar baz ?yabba ?dabba ?doo'
greple 'foo bar baz yabba|dabba|doo'
greple -e foo -e bar -e baz -e 'yabba|dabba|doo'

greple '?foo|bar ?yabba|dabba'  # foo|bar|yabba|dabba
greple 'foo|bar yabba|dabba'    # you want this? こーいうこと?

cut down the match count / マッチに必要な数をまける

greple --cut=1 'foo bar baz'

o foo bar baz
o foo baz
o bar baz
x foo

allow negative match / ネガティブマッチを許す

greple --allow=1 'foo -bar -baz'

o foo bar
o foo baz
x foo bar baz

narrow down the match result / 検索結果を絞り込む

greple pattern *.html
greple pattern *.html -v foo
greple pattern *.html -v foo -v bar
greple pattern *.html -v foo -v bar -v baz
# isn't this nice?
# これ、結構、よくないすか?

Areas / 領域

find and not in command / command に含まれない and を探す

greple --outside=command and

find from C comment / C のコメント部分を検索

greple --inside='(?s)\/\*.*?\*\/'

find from shell comment / シェルのコメントを検索する

greple --inside='#.*'

find variablish things from lines start with my / my ではじまる行から変数ぽいものを探す

greple --inside='^\s*my\b.*' '[\$\@]\w+'

Blocks / ブロック

paragraph mode / パラグラフモード

greple -p 'foo bar baz'

# show preveous and next paragraph together
# 前後のパラグラフも表示する   
greple -pC1 'foo bar baz' …

show paragraph not including pattern / 何かが含まれないパラグラフを表示する

greple --nocolor --re '(.+\n)+' -v '(?i)pattern'

show lines not including pattern / 何かが含まれない行を表示する

use grep -v !

show pages including pattern / ページ単位で表示する

greple -n --block='(.*\n){1,66}' pattern

show entire file / ファイル全体を表示する

greple --block='(?s).*'

show all comment blocks / コメントブロックを全部表示する

greple -o --nocolor --re '\/\*(?s:.*?)\*\/' /usr/include/stdio.h

Text / テキスト

複数行から検索する

greple 'リゾート|ステーション'
will match this text:
こんなのもみつけてくれます。
というか、日本語を処理する場合、そうでないと使い物にならないでしょ。

    長い駅名を探すと「東京ディズニーランド・ステーション駅」「リ
    ゾートゲートウェイ・ステーション駅」「東京ディズニーシー・ス
    テーション駅」「南阿蘇水の生まれる里白水高原駅」などが…

list up all Japanese Katakana words / 片仮名の単語を全部抜き出す

greple -ho --nocolor --join '\p{utf8::InKatakana}[\n\p{utf8::InKatakana}]*'

you like it? / 気に入ったらこんな風にどうぞ

cat >> ~/.greplerc
define :kana: \p{utf8::InKatakana}
option --kanalist --color=never --only-matching --join --re ':kana:[:kana:\n]+'

find cyclic redundancy c*

greple -pi -e 'cyclic redundancy c\w+' rfc*
greple -o --joinby=' ' -ie 'cyclic redundancy c\w+' rfc*

find Kanji and not CJKUnifiedIdeographs / 漢字だけど CJKUnifiedIdeographs じゃない文字を探す

greple --inside='\p{Han}+' '[^\s\p{InCJKUnifiedIdeographs}]'
# This works, but quite slow.  Not recommended.
# 動くけどチョー遅いからこんなことしちゃ駄目よ。

guess data encoding / 文字コードを自動判定する

greple --icode=guess

specify data encoding / 文字コードを指定する

greple --icode=euc-jp
greple --icode=shif-jis

specify guessing code set / 自動判定するコードを指定する

greple --icode=utf8,euc-jp,shift-jis,7bit-jis

add to guessing code set / 自動判定するコードを追加する

greple --icode=+euc-kr

Filter / フィルター

find from EXIF data / EXIF 情報を検索する

greple --if='env LC_ALL=en_US exif -x /dev/stdin' 'Image_Description|Manufacturer' *.jpg

MBPrintf の Github ページを作ってみた

Github Pages というのがあることを発見したので作ってみました。こんなカッコいいページが簡単に作れちゃうんですね。内容は大したことないんですが :-)。独自ドメインも使えるみたいだけど、それはまたそのうち。

 中身は、2年前に作った MBPrintf.pm という Perl モジュールのページですよ。マルチバイト文字を扱うための printf です。

EUC の場合は、何も考えずに printf で日本語を処理しても、大概の場合は期待通りに出るんですね。20年も使っている自前の住所録コマンドをやっと Unicode 対応にしたら、printf の表示が出鱈目になっちゃって、昔のコードを読み直して修正するのが面倒だったので、まんま printf を置き換えられるようにしたものです。やっつけですが、とりあえず何も考えずに置き換えれば動くので結構便利です。効率はいいとは言えないけど、変に考えてフォーマット文字列を作るとか、頑張って printf を使わずに出力するとかよりはマシかもしれません。

試してないけど、韓国語や中国語でも使えるんじゃないのかなあ。

そうそう、マニュアルに書き忘れていますが、mbwidth という関数を export すると表示幅がわかります。

ファイルハンドルも含めて、完全に printf と互換にできる方法を知っている人がいたら教えてください。

NAME
       MBPrintf − printf family functions to handle multi−byte characters

SYNOPSIS
       use MBPrintf;

       mbprintf(FORMAT, LIST)

       mbsprintf(FORMAT, LIST)

DESCRIPTION
       "MBPrintf" is a almost‐printf‐compatible library with a capability of
       handling multi‐byte wide characters properly.

       "MBPrintf" は、マルチバイト文字を処理するための、ほぼ printf と互換
       のライブラリ関数です。

FUNCTIONS
       mbprintf(FORMAT, LIST)
       mbsprintf(FORMAT, LIST)
           Use just like Perl’s printf and sprintf functions except that
           printf does not take FILEHANDLE as a first argument.

           使い方は Perl の printf, sprintf と同じです。ただし、ファイルハン
           ドルを指定することはできません。

IMPLEMENTATION NOTES
       Strings in the LIST which contains wide‐width character are replaced
       before formatting, and recovered after the process.  Number of replaced
       arguments are limited by 25.

       LIST 中に全角文字を含む文字列があった場合、整形処理を行う前に別の文字列に
       置換され、処理が終わった後で元に戻されます。変換する文字列の最大数は25に
       制限されています。

       Unique replacement string contains a combination of control characters
       (Control‐A to Control‐E).  So, if the FORMAT contains a string in this
       range, it has a chance to be a subject of replacement.

       置換文字列には制御文字 (コントロールAからコントロールE)が含まれるため、
       これらの文字が FORMAT に含まれている場合には注意が必要です。

       Wide‐character judgement is done based on Unicode property
       East_Asian_Width is Wide or FullWidth.  There is another value
       Ambiguous and treatment of this type characters are literaly ambiguous
       and is not considered now.  It might be better to use
       Unicode::EastAsianWidth instead.

       全角文字の判定は Unicode の East_Asian_Width プロパティが Wide あるいは
       FullWidth であることで行っています。これ以外に Ambiguous という値があり
       ますが、取り扱いが文字通り曖昧なため考慮していません。
       Unicode::EastAsianWidth を使った方がいいのかも知れません。

AUTHOR
       Copyright (c) 2011 Kazumasa Utashiro.  All rights reserved.

LICENSE
       See <http://www.perl.com/perl/misc/Artistic.html>

はてなの Facebook 連携も初体験。

Unicode 対応 mg

昔から使っている mg という文字列検索コマンドを2年ぶりに更新しました。

https://github.com/kaz-utashiro/mg

今回の変更点は以下の通り。

  • ファイルのデフォルト文字コードを utf8 にした。
  • ファイルのコード指定には -j オプションを使用する。
  • コードの自動判定を行う場合には -j Guess を指定する。

もしかすると、今まで Unicode 対応したことをアナウンスしていなかったかもしれません。基本的な機能は大きく変わっていませんが、Unicode 対応したことで検索文字列の指定にはかなり柔軟性が出てきたはずです。

Unicode 対応は、まだ実験的なコードとして実装されているため、他の機能と整合がとれていないこともあります。マニュアルの対応も完全ではないので注意してください。

2年前に書きかけた記事があったので、暇ができたら更新して公開します。



2013.10.23 追記:
オプションに -j を使うのはやめて、--icode と --ocode というオプションを作りました。

ファイルコードを指定 --icode=euc-jp
指定したコードから自動判定 --icode=euc-jp,jis
(区切りはスペースでもいい) --icode="euc-jp jis"
(複数指定してもいい) --icode=euc-jp --icode=jis
デフォルトのコードから自動判定 --icode=guess
デフォルトのコードに追加して自動判定 --icode=+euc-kr

当たり前かも知れませんが、Unicode に対応したことで日本語以外のテキストにも使えるようになりました。ちょっと感動です。



2013.10.24 追記:
バイナリファイルを検索する -B オプションと、テキストファイルだけを検索する -T オプションは、Unicode 対応機能と整合性が悪いため廃止しました。