/ 最近 .rdf 追記 設定 本棚

脳log[2008-05-30~]



2008年05月30日 (金) ViewVCに URLをパラメータとして与えて、外部の生Subversionリポジトリに ViewVCの皮をかぶせたい。

[SHJS] 続・shjs-0.4.2: 重箱の隅、つっつきます

$ で GREPしてみたらこういうものが無数に見つかった。だいたいが一行コメントの中に対応した state。終了条件は行末で、URLを含んでいれば sh_urlとしてマークする。

    {
      'exit': true,
      'regex': /$/g
    },
    {
      'regex': /(?:<?)[A-Za-z0-9_\.\/\-_]+@[A-Za-z0-9_\.\/\-_]+(?:>?)/g,
      'style': 'sh_url'
    },

URLが改行の直前まで続いていれば、終了条件としての行末の検出がスキップされて一行コメントが次の行まで継続する。まさしく 20080513p01の問題の繰り返し。

結局、sh_main.jsに非互換な変更を加えるのは問題大ありだと判明したので sh_javascript.jsで対応することにしましたよ、と。

  [ // state 2: in "string"
    {
      regex: /\\[\\"]/g
    },
    {
      next: 6,
      regex: /\\$/gm
    },
    {
      exit: true,
      regex: /"|$/gm
    }
  ],
  [ // state 6: eat an end-of-line ※空行は食べられないよ
    {
      exit: true,
      regex: /^/gm
    }
  ]

動作確認は昨日の日記で。


2008年05月29日 (木) 内容と関係のない画一的な帯は間違いなくゴミ(コバルト文庫のことです)。帯の下を意識させるデザインのときの帯もゴミ。役に立つ文字が書いていない帯もゴミ。帯を外すと間抜けなカバーはダメダメ。(最近は買った本の帯をカバーの下に隠すことが多い。<でも捨てられない)

[SHJS] shjs-0.4.2: 重箱の隅、つっつきます

例えば、JavaScriptのリテラル文字列では \ と改行のシークェンスは空文字を意味している。つまりこういうこと

var str = "空白を含まない\
ひとつながりの文字列です";

このシークェンスを認めるように、ダブルクォーテーション文字列の終了条件として次のようなものを shjs/lang/sh_javascript.js に含めてみたがうまくいかなかった。

  [ // "string"
    {
      // \\ と \" と \(改行) を 1つのシークェンスとして
      // 食べてしまう。終了位置を見誤らないためであって、
      // 特に何をするということもない。/\\(.|$)/gm でも構わない。
      regex: /\\(?:[\\"]|$)/gm
    },
    {
      // エスケープされていない " に出会ったら "~" の中に
      // いるという状態(state)から exitする。
      // " がないまま行末に達したら、終端されていない不正な
      // 文字列だと判断して、やはり exitする。
      exit: true,
      regex: /"|$/gm
    }
  ],

少し前に「行末に達した時点でマッチングを打ち切っていたのが間違い。$は空文字列にもマッチする。全てのマッチに失敗するまで続ける必要があった(20080513p01)」と自分のミスを書いて、これを修正したのだが、shjs-0.4.2はもちろん正しく、全てのマッチが失敗するまで続けている。

そうすると何が起こるか。/\\$/gm にマッチした後でも /"|$/gm のマッチに成功してしまい、結果、行末に \ があろうがなかろうが exitしてしまう。

もちろん行末に達したからといってすぐにマッチングを打ち切っては 20080513p01と同じ間違いを犯すことになるので、同一 state内で*二回以上*行末にマッチすることがないように sh_main.jsを変更した。

内の方のループの、頻繁に実行される部分に if が増えたのが気に入らないものの、悪影響のある非互換でもないし、首尾は上々だし(冒頭の文字列のハイライト結果が見本)、悪くない。

var str = "終端されていない
不正な文字列です";

 追記@2008-05-30: この場合はどうする?

var str = "終端されていない\"
不正な文字列です";

*たまたま*行末にある \" にマッチしたことで、終了条件である行末の検出がスキップされて、次の行までが文字列だと判断されている*。\" とのマッチは \$ と違い行末を要求していないから、この場合は一行目で exitしてほしい。

* 20080530p01で修正したので文章とハイライト結果が食い違っているかもしれない。


2008年05月28日 (水) コンテントネゴシエイションによる表示言語の切り替えはうまくない。内容が同じなら日本語で表示された方が読みやすいが、英語の方が情報が新しいのが常。Accept-Languageを切り替えるより URLを書き換える方が圧倒的に楽でしょう。読み手に選択肢を! >>>>>>http://www.mozilla.com/firefox/

[正規表現] 今日やられた正規表現

/^(?=\W)/
/^(?!\w)/

二つの違いは? (ヒント:空文字列/空行)


/^(?=\W)/  //=> 単語に使われる以外の文字から始まる行の頭にマッチ
/^(?!\w)/  //=> 単語に使われる文字から始まらない行の頭にマッチ
           //   (最初のパターンと違い、一文字もない場合(空行)にもマッチする)

2008年05月27日 (火) [Firefox] 領域を選択してのソース表示は、スクリプトに書き換えられた最新の HTMLを反映しているのが便利。

[Firefox][javascript][SHJS] <pre>が真っ白になり、黒色の領域が出現する。

例えばこのページ http://vvvvvv.sakura.ne.jp/ds14050/diary/20080112-7.html 。Endキーで末尾に移動して PageUpで戻っていくと空白の PREが目に入ると思う。その少し上にはページの内容を覆い隠す黒い領域があるはず。(そうでなければ修正されたのだろう。Firefox2で最初に確認し、Firefox3.0RC1でも直っていなかったが)

大量の PREが存在したり、一つだけでも巨大な PREが存在する場合に起こる様子。innerHTMLで PREの内容を置き換えているのも原因になっているかもしれない。

画面の末端にスクロールした状態でページをリロード(F5 or Ctrl+R)すると下方の PREが正常に表示される反面、上端付近の PREに同じ問題が生じる。遠方の PREの書き換えに問題があるのでは?

真っ白の PREの中で、右クリックしたりテキストを選択したりといったアクションを起こせば正常に表示されることが多い。


あと、PREの中から開始した選択は PREの外に出られなかったり。(これは TEXTAREAと違い PREでは Ctrl+Aで全文選択ができないために用意された代替手段だという気もする)


2008年05月26日 (月) 今の自転車で初コケ。低速で曲がるときにハンドルを180°回転させてしまった。


2008年05月25日 (日) 自転車で30分かかる道のりを20分で帰ってきたのに始まる気配がない。また野球か、と思ったらバレー。最大60分の延長。疲れた。


2008年05月23日 (金) (個人的)最近のアニメ:xxxHOLiC◆継、らき☆すた、少女革命ウテナ、serial experiments lain、成恵の世界


2008年05月20日 (火) Mercurialのコマンドが hgな理由をアオイシロに発見。(って単なる英語と元素記号だったんだけど……。自分にとって英単語ってのは中身のない識別記号にすぎないんだなあ)


2008年05月15日 (木) 正規表現の存在を知り、その文法を知ったのは JScript5.5の HTMLヘルプだった。ほんとう、役に立つドキュメントだった。(>20080215p01) 「だった」といいつつ、今も持っていて参照もしているけれど。

[Ruby][正規表現] /n, /s, /e, /u, $KCODEのもやっとを解消

正規表現リテラルの /nseuフラグは正規表現のマッチ動作に影響を与える。(/nseuフラグのいずれも指定しなかった場合は実行時の $KCODEに従う)

/nが指定されていたり $KCODE='NONE'のとき、「.」は改行を除いたり改行を含んだりする 1バイトにマッチするメタ文字だが、/seuフラグが指定されていたり $KCODEが SsEeUuのいずれかで始まる文字列のとき、「.」は日本語を含む、Shift_JIS、EUC-JP、UTF-8の一文字(1-3?バイト)にマッチする。

/nseuフラグや $KCODEは正規表現のパターンの解釈にも影響を与える。

Shift_JISで保存したスクリプトファイルに /表w/ というパターンと '表w' という文字列リテラルがあり、マッチを行った場合。実行時に $KCODE='NONE'であればパターンは /\225\w/ と解釈され、"\225"の後にメタ文字 \wにマッチする文字を探し、失敗する。$KCODE='SJIS'であればパターンは /表w/ と解釈され、"表"のあとに "w"を探し、成功する。

irb(main)> /表w/n =~ '表w'
=> nil
irb(main)> /表w/s =~ '表w'
=> 0

正規表現パターンの中のマルチバイト文字は文字列の場合と同じく、あくまでバイト列であり、/nseuフラグや $KCODEがどうであれ EUC-JPで保存されたスクリプトの中の正規表現リテラル /あ/ は Shift_JISの「あ」を表すバイト列 "\202\240" にマッチすることはない。


2008年05月14日 (水) DFAエンジンのマッチの仕組みは謎のまま残された。正規表現を利用する側からはコントロールできる部分が皆無で、常に同じ結果が返ってくるおもしろみのないものらしいけど、その魔法の実現方法は大いに知りたい。

[正規表現][javascript][大型本] Jeffrey E.F. Friedl【詳説 正規表現 第3版】 オライリージャパン

読んだ。この日記で以前書いたようなこと(20080116p01, 20080111p01)は全て書いてあった。もちろんそれ以上に知らないこと(NFAのマッチングのしかた、NFA型正規表現エンジンに適用できる正規表現のチューニングの具体例、Unicodeサポート、Perl, .NET, Java, PHPの正規表現、\Gの使い方などなど)が書かれていた。

非常に読みやすい文章で書かれているし、必要なところでは必ず前後のページへの参照先が書かれている。章の始めには Overviewがあり、その章から読み始めた読者への配慮も忘れない。当たり前のことだけど、徹底されている。「まずこの本を読め。正規表現について話すのはそれからだ。」と言い切れる良い本。正規表現を初めて学ぶ人にも、効率について考える余地ができてくるほど既に正規表現を使っている人にも役に立つ。

すごく実用的なテクニックで、でも全く想像が及ばなかったものがある。168ページの「4.5.8.1 肯定の先読みを使ったアトミックグループの模倣」がそれ。

 肯定の先読みを使ったアトミックグループの模倣

/(?>pattern)/     // アトミックグループを使ったパターン
/(?=(pattern))\1/  // 先読みでアトミックグループを模倣したパターン

高機能化する他の実装にくらべて、昔のままの JavaScriptの正規表現はバックトラックを抑制する構文を持っていない。JavaScriptでは非常に有用。

20080116p01でも書いたが、次の終わらない正規表現

/"(?:[^\\"]+|\\.)*"/       // マッチに失敗するとき死ぬほど遅い

はアトミックグループや絶対最大量指定子が使えるなら次のように書けるが JavaScriptは両方ともサポートしていない。

/"(?:[^\\"]+|\\.)*+"/      // JavaScriptでは使えない
/"(?>(?:[^\\"]+|\\.)*)"/g  // JavaScriptでは使えない
/"(?:[^\\"]++|\\.)*"/      // JavaScriptでは使えない。※上2つとは少し意味が違う

次のように先読みでアトミックグループを模倣すると組み合わせの爆発を避けることができる。

/"(?=((?:[^\\"]+|\\.)*))\1"/
/"\1"/            // 上のパターンから先読み部分を取り除いたもの。

先読みを取り除いたパターンを見ると一目瞭然だが、引用符がペアになっていなくて \1 の後ろの " のマッチに失敗したとしても戻る場所がない。あるのは " と \1 にマッチしたという結果で、どちらもオプションではないので取り消すことはできず、繰り返しでもないのでマッチした部分を少しずつ手放させることもできない。なので、ちょっとずつ後じさりしながら延々とあらゆる組み合わせのマッチを試行することなしに、マッチが失敗に終わったことが即座に判断できるようになるというわけ。本物のアトミックグループよりは劣るが効率も悪くない。同じ働きをする次の二つのパターンとかかる時間を比較してみた。

/"[^\\"]*(?:\\.[^\\"]*)*"/
/"(?:[^\\"]|\\.)*"/

 手順

バックトラックによる組み合わせの爆発が起きない 3つのパターンでかかる時間を比較。3回実行した。(3回繰り返しても一回一回の中の試行順が固定されていたら傾向は同じになるわな。無意味。あてみやむいみ)

var re = [
	/"(?:[^\\"]|\\.)*"/,
	/"(?=((?:[^\\"]+|\\.)*))\1"/,
	/"[^\\"]*(?:\\.[^\\"]*)*"/
];
var s = [
	'"'+ new Array(5000+1).join('\\"'),        //  1/100
	'"'+ new Array(500000+1).join('\\"') +'"',
	'"'+ new Array(500000+1).join("\\'"),
	'"'+ new Array(500000+1).join("\\'") +'"',
	'"'+ new Array(500000+1).join('a'),
	'"'+ new Array(500000+1).join('a') +'"'
];
var results = [];
for(var j = 0; j !== s.length; ++j) {
	var result = [];
	for(var i = 0; i !== re.length; ++i) {
		var t0 = new Date();
		var m = re[i].exec(s[j]);
		result[i] = new Date() - t0;
	}
	results[j] = result;
}
WScript.Echo(results.join("\n"));

 結果

数の単位は msec。

パターン1パターン2パターン3
工夫なしアトミックグループの模倣ループ展開
/"(?:[^\\"]|\\.)*"//"(?=((?:[^\\"]+|\\.)*))\1"//"[^\\"]*(?:\\.[^\\"]*)*"/
文字列1マッチしない(F)"\"\"......\"\"2910×100, 2928×100, 2914×1002551×100, 2581×100, 2595×1002372×100, 2387×100, 2377×100
マッチする(T)"\"\"......\"\""124, 124, 124138, 137, 134108, 107, 108
文字列2マッチしない(F)"\'\'......\'\'138, 140, 151125, 127, 125122, 118, 118
マッチする(T)"\'\'......\'\'"138, 126, 126140, 128, 133135, 105, 106
文字列3マッチしない(F)"aa..........aa174, 172, 16614, 11, 1396, 90, 92
マッチする(T)"aa..........aa"155, 119, 12632, 15, 1415, 12, 11

 みどころ

  • マッチに失敗するときの、成功するときに比べた遅さ。
    • パターン2は例外
  • パターン2(アトミックグループの模倣)ではしばしばマッチに失敗する方が速い。
    • \1のマッチが成功だと判断するにはキャプチャした長い長い文字列を最後までたどって比較する必要があるため、\1のマッチに失敗するほうが速くなる?
  • 文字列1Fの特筆すべき遅さ。
    • 遅いとはいえ「終わらない」と形容するほど遅くはない。(これでも!)
    • 文字列長に比例したバックトラックが行われているせい?
    • 文字列2Fの結果と比較するに、\" という形で " が文字列の途中に含まれていることが最適化を阻んでいる?
  • パターン3(ループ展開)は特定の場合を除いてパターン2(アトミックグループの模倣)より若干速い。
    • ループ展開は『詳説 正規表現』に載っていた言葉。
    • 特定の場合とは文字列3Fのことで、不用意なパターンを用いると処理が終わらなくなる場合のこと。
  • パターン2(アトミックグループの模倣)は、(今回の眼目である)組み合わせの爆発が起こるような場合に、顕著な速さを見せる。
    • 他の文字列ではパターン3(ループ展開)に半歩譲るが。

ところで、文字列1Fがどのパターンでも一様に遅いのは文字列長に比例したバックトラックが行われているからなんだろうが、パターン2(先読みによるアトミックグループの模倣)でもそれを抑制できていないのは、なんとかできないものか。それでこそ若干のオーバーヘッドをのんででもアトミックグループの模倣を採用する理由になるのだが。


2008年05月13日 (火) qr/…/と同じものは Rubyにないと思っていたが Regexp#to_sがそれ。正規表現リテラルの式展開と組み合わせて使おう。hikidoc.rbでは昔から使われていたのに何を見ていたのか。

[SHJS] URLのハイパーリンク化とバグ潰し

オリジナルの sh_javascript.jsはコメントの中の URLっぽい部分とメールアドレスっぽい部分をハイパーリンクにしていた。機能が劣るのは遺憾なので sh_javascript.jsと sh_ruby.jsに、コメントと文字列の中の URLっぽい部分をハイパーリンク化する機能を追加した。

その過程で気付いた、一行コメントの終了条件などに使われている $アンカーのマッチングが行われない場合があったのを修正した。(行末に達した時点でマッチングを打ち切っていたのが間違い。$は空文字列にもマッチする。全てのマッチに失敗するまで続ける必要があった)。これは自分が 2008-02-25に持ち込んだバグでオリジナルには存在しない。

 サンプル / テストケース

  • 一行目:コメント内の URLはリンクになっているか?
  • 二行目:一行目のコメントの続きだと誤認されていないか?
# http://vvvvvv.sakura.ne.jp/ds14050/badboy/log/
How is this line highlighted ?

 最新の、未来において変更されている可能性のあるファイルへのリンク


2008年05月11日 (日)

[Firefox] Firefox 3 beta 5の faviconがおかしくなったので

アイコンキャッシュを全削除。

>sqlite3 places.sqlite
sqlite> DELETE FROM moz_favicons;

favicon.icoが存在しないサイトの faviconが何かの拍子に別のサイトの faviconになってしまうことが何度かあった。(そしてそのサイトには favicon.icoがもともと存在しないため、更新されることもなく間違え続ける)


2008年05月08日 (木) [Vista] 「プログラムから開く」が便利なんだけどフォルダを対象にできないのが玉に瑕。Unknown\shell\openasを directory\shell\openasにコピーするとダイアログを開くことはできるがプログラムのリストがコンテクストメニューに展開されたりはしない。

最終更新: 2009-09-01T05:05+0900

[SHJS][Ruby] '%04d-%02d-%02d' % [2008, 5, 8] がうまくハイライトできない理由

このようにハイライトされます。

'%04d-%02d-%02d' % [2008, 5, 8]

(整形した)HTMLソースはこう。

<span class="sh_string">'%04d-%02d-%02d'</span> 
<span class="sh_string">% [2008, </span>
<span class="sh_number">5</span>
<span class="sh_symbol">,</span> 
<span class="sh_number">8</span>
<span class="sh_cbracket">]</span>

「% [2008, 」が一つの文字列にされてしまっている。どういう判断なのかと調べれば、%!string! と同じものだと見なされていた。(そのルールは自分で書いたんだけども)

知っていたでしょうか? %リテラルの区切りには空白(改行も!)が使えるのでした。(alnumと mbchar以外なら OKっぽい。変態すぎるよ)

最終更新: 2010-07-05T10:38+0900

regexpと書いて正規表現と読む

[大型本] Jeffrey E.F. Friedl【詳説 正規表現 第3版】 オライリージャパン

この本の著者は regex派だそうな。FedExと同じように読めるからだとか。自分は気分で regexだったり regexpだったり reだったり。regexpって書く人はどう読んでんの? だって。そうか、読み方か。考えたこともなかった。Friedlさんの疑問にお答えしましょう。regexpと書いて正規表現と読む、です。


iPodを始め、よそでは 12:00 PM が正午を意味することについて(無理矢理)理由を考えてみました。

12:00-12:59が 12:00PM-12:59PM、00:00-00:59が 12:00AM-12:59AMになる理由。日本人の(と書いてもいいよね?)感覚では 12:00PM=00:00AM=深夜となるものが正午を表してしまう理由。

時刻と AM/PMをわけて考えなければいけない。まず、時刻の部分はそのまま読み方を表している。だから 0時台は存在せず 12時台が使われる (0時何分という読み方をする人もいるでしょうが、自分は 12時何分と読みます。時計の文字盤にも 0は無いし。本当の問題は海の向こうの人がどう読むか、ですが)。そして、AM/PMは午前か午後かを付加的に表している。

  • 「今何時?」
  • 「12時半」「午後の」
  • => 12:30 PM

こじつけすぎるか……。(AM/PMが(午前/午後と違い)時刻の後ろに付くのは確かなんだけど)

00:30と書いて 12時30分と読んだり、午後0時半と読んだり、ひょっとしたら午後12時30分と読んだりする器用さが無いのが理由なんじゃないかと思ったのだが。*


 追記@2009-05-30: 午前!=AM。午後!=PMということだったの……か?

自分のケータイでこっそりこんな修正が行われていた。

サブディスプレイの待受画面に表示される時計を「Digital1(12h)」にすると、0時(午前0時)台が0:xxAM、12時(午後0時)台が12:xxAMと表示される。(他の12時間表示では、正しくそれぞれ12:xxAM、12:xxPMと表示される)

午前0時台は 0:xx AMではなく 12:xx AMが正しいと書いてある。

午前と午後 - Wikipedia

同じく Wikipedia。日本でも海外でもいろいろあるみたいね(なにが正しいとは言い切れない)。でも日本の公の判断が理性的で良い。だから AM/PMなんて使わずに午前/午後を使うべき。一番面倒がないのは 24時間制を使うことだし、もちろん自分のデジタル時計は全てそうしてるけど。

* 自分は 19:00と書いて 7時(ななじ)と読む人間なので可能な限り 24時間表記。午前とか午後とか気にしたくない。military timeだからって嫌う人がいるなんて信じられないよ。

 auの情報が不完全だから。