From: Minero Aoki Date: 2001-08-19T12:22:50+09:00 Subject: [ruby-list:30987] [REQ] String#slice(re, n) あおきです。 Regexp#match! のスレッドにおつきあいくださったみなさん、どうも ありがとうございました。反論に対していろいろ考えているうちに もともとやりたかったこと、気にくわなかったことがより鮮明になって きたので、今度は別の提案です。 Regexp#match! を提案する原因になったのはそもそも m = re.match(str) or raise .... m[1] と書くときにローカル変数を使うのがイヤ、ということでしたが、 もしかしたらこの形を使うという前提がよくなかったんではないかと 思いはじめました。というのは、本当にやりたいことが 正規表現にマッチする部分文字列の取り出し であるのに対して 1. match して 2. MatchData をもらって 3. インデクシングで結果を取る というやりかたがそもそもまどろっこしいというか、間接的にすぎる。 また単にローカル変数を使わないといけない、ということではなく、 MatchData というなんか正体の見えない中間結果をローカル変数に 入れなきゃいけない、というのが納得いかない点でした。 そこでもっと直接的に「正規表現を使った部分文字列の取り出し」を するメソッドがあればいいのではないか、と考えました。一方あらためて メソッドをながめてみると、すでに String#slice(re) で文字列から 正規表現にマッチした部分を取り出すことができます。これを拡張して : slice(re, n=0) re の n 番目のレジスタにマッチした部分を返す。 とするのはどうでしょうか。そうすると cname = str.slice(re, 1) or raise .... みたいに書けて、少なくとも中間ローカル変数には意味のある値を入れ られるし、その値で分岐するんだったら納得がいきます。 もちろん既存のメソッドを使っても cname = re.match(str).to_a[1] or raise .... とすることはできます。しかしこれでは間接的すぎるのがイヤです。 そもそも MatchData というもの自体が「マッチという主作用にくっ ついてくる副作用」という感覚があるので、さらにそこから to_a なんて抽象化層をかませてしまうと非常に感覚から乖離してしまいます。 一言で言うと、やっていることをイメージできないんです。だから これではイヤです。付け加えると、str がでかい場合には to_a で 巨大な文字列が生成されてメモリも無駄です。 (以下蛇足) == 「機能はいいが名前がよくない」と言われた場合に備えた追加 現在 slice には二つの機能があると思います。ひとつはインデックス によるスライス、ふたつめは中身によるスライスです。 * インデックスによるスライス str.slice(n) str.slice(start,len) str.slice(begin..end) * 中身によるスライス str.slice(substr) str.slice(re) これをひとつのメソッドで行っているのがそもそも過剰と思えるので、 slice がやるのはインデックスによるスライスだけにとどめ、中身に よるスライスは別のメソッドにします。たとえば extract とか matched とか……。んで、[] (aref) にはユーティリティとして両方の機能を 持たせます。 == [追加提案] 一度に複数の部分マッチを取る 取りたい部分マッチがひとつではないことも多いと思います。それに 備えてインデックス部分に配列を渡せるようにするのはどうでしょう。 # 例 substr1, substr2, substr3 = str.slice(re, [n1, n2, n3]) これは a = re.match(str).to_a.indexes(n1, n2, n3) に相当します。が、こっちはすごく欲しいというほどではないです。 あれば便利かなあ、くらい (多重代入だから条件式に使えないし)。 == think also? ずっと前から何回も出てくる「一回しか scan しない scan」をもう 一度考えるいい機会かもしれない。機能的に似ている。 ------------------------------------------------------------------- 青木峰郎