Gauche:regexp
\w は _ にマッチしないのですね
satoru Perl や Ruby と違って Gauche の \w は _ にマッチしないのですね。 勘違いしていてちょっとはまりました。
- Shiro: 今のところ\w == [[:alpha:][:digit:]] にしてありますが、 別にポリシーがあってそうしたわけではないので、 '_' を入れるのがde factoであればそちらに合わせます。 ('_'をword constituentと考えるのはC的な文化かなあ。)
- → Gauche 0.6.8 からは _ にもマッチするようになりました。
^ は文字列の先頭ではなく行頭にマッチして欲しいな
satoru ^ は文字列の先頭ではなく、行頭にマッチするという仕様のほうが便利だと思うんですが、いかがでしょう。
gosh> (rxmatch #/^foo/ "foo") #<<regmatch> 0x81a8a80> gosh> (rxmatch #/^foo/ "abc\nfoo") #f
Ruby では ^ は行頭にマッチします。 文字列の先頭にマッチさせるには \A を使います。
% irb >> /^foo/ === "foo" => 0 >> /^foo/ === "abc\nfoo" => 4 >> /\Afoo/ === "foo" => 0 >> /\Afoo/ === "abc\nfoo" => nil
Perl では /m を指定すると ^ が行頭にマッチするようになります。 この辺は処理系によってまちまちでややこしいすね。
Shiro: いくつかの理由で、Gaucheのregexpでは「行」という概念を意図的に落してあります。
- 「行末」の定義がプラットフォーム依存のうえ、入出力でも変更を受けることがあり、常に正しく結果を予測することが難しい (「大抵動くけど、たまに噛み付かれる」というプログラムのもと)。
- 例えば、'$'が行末にマッチするとして、 #/.*$/ を "a\n" "b\r\n" "c\r\r\n" "d\r" にマッチさせた時、 それぞれのマッチ文字列はどうなるべきか。
- 行指向か否かでメタキャラクタのセマンティクスが変わる。特に、'.' が\nにマッチするか否か、等根本的な部分が変化する。
- むしろ、レコードの分離はアプリケーション側で行い (「行」もレコードの一種)、レコード内解析をregexpで行うことを推奨。
- 本来、'^'や'$'が行頭、行末一致だったのは、ed等のアプリケーションが 「行」という概念の面倒を見ていたから。それを切り出して文字列に対して マッチさせようとした途端、セマンティクスの分裂が起きた。レコードの処理が アプリケーション側で行われるedやsedならともかく、 スクリプト言語ならregexpに喰わせるレコードを自前で準備できるわけなんで、 余分なセマンティクスをregexpに入れるよりはアプリ側で記述する方が明確だと 考える。
- そうは言っても良く書く処理は短く書けるべき、という哲学もまた正しいので、 「行頭、行末」assertionを入れることはやぶさかではない。ただし、 入れるなら「単語の先頭、末尾」assertion等と同じレベルのassertionにするだろう。
大文字小文字の区別をしないマッチング
satoru 正規表現のマッチングで大文字小文字の区別をしないようにする方法はありますでしょうか? Perl や Ruby っぽく #/abc/i のように書けるとうれしいです。
% irb >> /abc/i.match("AbC") => #<MatchData:0x401e8034>
- Shiro: これ、実装方法を迷っていて保留にしてあります。 確か昔のBSDのregexpだったかは、case insensitiveの場合全ての文字を /[aA][bB][cC]/のように展開してコンパイルしていました。 あるいは、マッチング文字列の方のcaseを揃えるという方法もあるでしょう。
- しかし、最大のネックは「大文字」「小文字」という概念が、 ASCIIの範囲をはみ出したとたんえらく大変になってしまうことです。 一応Unicodeではそのへんが定義されてはいますが、 まともに書くのは時間がかかりそうですし。
- ま、今でも string-ci=? 等はASCIIの範囲しか見ないので、 とりあえずその範囲でやっちゃえ、というのもアリかな。
- satoru メールを処理するプログラムを書いているんですが、ヘッダに現れる文字列が "iso-2022-jp" だったり "ISO-2002-JP" だったりして困っています。ASCIIの範囲でいいので、実装してもらえると助かります。
- satoru #/abc/ => #/[aA][bB][cC]/ の展開を自前でやろうかと思いましたが、 #/[a-z]/ みたいな文字クラスがあると面倒ですね。 文字列の方のcaseをそろえるという方法の場合でも、正規表現の方のcaseもそろえる必要があるのでやっぱり面倒そうです。(文字列の方を内部的に全部小文字にした場合、正規表現の方もすべて小文字にして扱わないといけない)
- satoru #/abc/ => #/[aA][bB][cC]/ の展開をちょっとやってみました。 文字クラスの中はいじらないという方針にしました (気をつけたつもりですが、穴があるかも)。なかなか涙ぐましいコードです。最初は string->list して一文字づつ処理しようとしたんですが、面倒になってきたので正規表現でえいやーとやりました。
(define (rxstring-expand-ci str) (regexp-replace-all #/([^[\\]*)(\\.|\[^?]?[^]]+\])?/ str (lambda (m) (string-append (regexp-replace-all #/([a-zA-Z])/ (rxmatch-substring m 1) (lambda (mm) (string-append "[" (string-downcase (rxmatch-substring mm 1)) (string-upcase (rxmatch-substring mm 1)) "]"))) (or (rxmatch-substring m 2) "")))))
(define (test str) (format #t "~s => ~s\n" str (rxstring-expand-ci str)))
(test "aBc") (test "aBc[a-z]dEf") (test "aBc[]a-z]dEf") (test "aBc[^]a-z]dEf") (test "aBc[.]a-z]dEf") (test "aB\\[\\nc[.\\]a-z]dEf")
実行結果:
"aBc" => "[aA][bB][cC]" "aBc[a-z]dEf" => "[aA][bB][cC][a-z][dD][eE][fF]" "aBc[]a-z]dEf" => "[aA][bB][cC][]a-z][dD][eE][fF]" "aBc[^]a-z]dEf" => "[aA][bB][cC][^]a-z][dD][eE][fF]" "aBc[.]a-z]dEf" => "[aA][bB][cC][.][aA]-[zZ]][dD][eE][fF]" "aB\\[\\nc[.\\]a-z]dEf" => "[aA][bB]\\[\\n[cC][.\\][aA]-[zZ]][dD][eE][fF]"
- Shiro: 直球勝負っすね。 ちとregexpエンジン内でさりげなくフラグを立てていけないかどうか 考えてみます。むしろ構文なんですが、PerlやRubyみたいに フラグを後置するのは一文字先読みするだけなのでやってやれなくは無いけれど、 あんまりSchemeっぽくないっすね。#i/abc/ の方がよさげだけど、 #iはinexact number prefixに使われちゃっているしなあ。 うむむむ…
- Shiro: 実装しました。0.6.3に入ります。結局 #/abc/iという構文を採用。 string->regexpにはcase-foldというkeyword argumentが追加されます。 キャラクタクラスもcase-foldされます。(2002/09/20 20:11:55 PDT)
(cond ((rxmatch #/ab[a-z]ef/i "ABCEF") => rxmatch-substring) (else #f)) ==> "ABCEF"
- Shiro: ちなみに、0.6.3では任意のオブジェクトを適用可能にすることが できるようになります。それを利用して、<regexp>オブジェクトと<regmatch> オブジェクトを適用すると、それぞれrxmatch, rxmatch-substring (またはrxmatch-{before,after}) の動作をするようになります。 コードがかなりコンパクトに書けるようになるのではないかと。
(rxmatch #/abc/ string) ≡ (#/abc/ string) (rxmatch-substring m 1) ≡ (m 1) (rxmatch-after m) ≡ (m 'after) (map (lambda (i) (rxmatch-substring m i)) '(1 2 3) ≡ (map m '(1 2 3))
正規表現オブジェクトからパターンの元の文字列を知しりたい
satoru 正規表現オブジェクトから、パターンの元の文字列を知ることはできないでしょうか? regexp->string があるとうれしいです。
% gosh gosh> #/foo/ #<<regexp> 0x8193340>
ちなみに、Ruby では Regexp#inspect で知ることができます。
% irb >> /foo/ => /foo/ >> /foo/.inspect => "/foo/" >> /foo/.to_s => "#<Regexp:0x401e8ca0>"
あと、regexp? がなかったので次のコードでごまかしました。
(define (regexp? obj) (is-a? obj <regexp>))
- Shiro: なるほど、これはあると便利かな。今はコンパイル後のデータしか 保存していないのですが、コンパイル前の文字列も保存するようにしてみます。 多分、スロットとしてアクセスできるようにするかと思います。 regexp? も追加しときます。(2002/09/18 11:46:17 PDT)
参考
Tag: 正規表現