[#21225] Re: [ruby-cvs] ruby: * enum.c (inject_i): use rb_yield_values. — "U.Nakamura" <usa@...>

こんにちは、なかむら(う)です。

14 messages 2003/08/22
[#21227] Re: [ruby-cvs] ruby: * enum.c (inject_i): use rb_yield_values. — nobu.nakada@... 2003/08/22

なかだです。

[#21228] Re: [ruby-cvs] ruby: * enum.c (inject_i): use rb_yield_values. — matz@... (Yukihiro Matsumoto) 2003/08/22

まつもと ゆきひろです

[#21281] 大量メモリ消費攻撃に対する対応 — Hidetoshi NAGAI <nagai@...>

永井@知能.九工大です.

16 messages 2003/08/29
[#21285] Re: 大量メモリ消費攻撃に対する対応 — matz@... (Yukihiro Matsumoto) 2003/08/29

まつもと ゆきひろです

[#21288] Re: 大量メモリ消費攻撃に対する対応 — Hidetoshi NAGAI <nagai@...> 2003/08/29

永井@知能.九工大です.

[#21306] Re: 大量メモリ消費攻撃に対する対応 — matz@... (Yukihiro Matsumoto) 2003/09/03

まつもと ゆきひろです

[ruby-dev:21146] Regexp.alt(pat1, pat2, ...)

From: Tanaka Akira <akr@...17n.org>
Date: 2003-08-05 10:13:48 UTC
List: ruby-dev #21146
提案なのですが、複数の Regexp (や String) を | でつなぐ Regexp.alt
というメソッドを用意しませんか。

つまり、

  rs = [/a/, /b/, /c/]
  Regexp.alt *rs
  #=> /(?-mix:a)|(?-mix:b)|(?-mix:c)/

というようなものです。

実装は、次のようなもの(を C で実装したもの)を想定しています。

def Regexp.alt(*args)
  case args.length
  when 0
    /(?!)/
  when 1
    if Regexp === args[0]
      args[0]
    else
      arg = args[0]
      if arg.respond_to? :to_str
        arg = arg.to_str
      else
        raise TypeError, "cannot convert #{arg.class} to String"
      end
      Regexp.new(Regexp.quote(arg))
    end
  else
    code = nil
    source = args.map {|arg|
      if Regexp === arg
        if arg.kcode 
          if code && code != arg.kcode
            raise ArgumentError, "mixed kcode: #{args.inspect}"
          end
          code = arg.kcode
        end
        arg.to_s
      elsif arg.respond_to? :to_str
        Regexp.quote(arg.to_str)
      else
        raise TypeError, "cannot convert #{arg.class} to String"
      end
    }.join('|')

    Regexp.new(source, nil, code)
  end
end

用途はそれなりにあって、標準添付のライブラリをざっと眺めただけでも次の
ものが見つかります。

lib/cgi.rb:      string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
lib/cgi.rb:      string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/ni) do
lib/date/format.rb:  PARSE_MONTHPAT = ABBR_MONTHS.keys.join('|')
lib/date/format.rb:  PARSE_DAYPAT   = ABBR_DAYS.  keys.join('|')
lib/uri/common.rb:                        }.join('|') + ')' + PATTERN::X_ABS_URI, 
lib/webrick/httpserver.rb:        @scanner = Regexp.new("^(" + k.join("|") +")(?=/|$)")

また、私が最近書いたプログラムでも、2ヶ所、関係ないクラスの実装で必要
になり、プログラムのクラスのメソッドとするよりも、Regexp のメソッドと
するほうが適切だと思いました。(だからこうして提案しているわけですが。)

また、join('|') には次のような微妙な点があり、ただ join('|') するだけ
では潜在的に問題が発生する可能性があるため、ユーザに join('|') を書か
せるよりもプリミティブとして提供したほうが良いと思います。

* 引数が 0個の場合、| の単位元のφに対応する、まったくマッチしないパター
  ン (たとえば /(?!)/) にするのが適切なのに、join('|') だと空文字列に
  マッチするようになってしまう。

* join('|') はパターンを String として扱わなければならず、昨今の傾向に
  そぐわない。(String 中のメタキャラクタが効いてしまう)

* 1.9 への互換性を考えた場合、kcode が混ざっている場合は例外にするのが
  適切な気がするけれど、1.8 の join('|') だと検出されない。

なお、
Regexp.alt *rs は
rs.join('|') よりもちょっと長いわけですが、Regexp リテラル中の一部で使
われる場合には join('|') は (?:...) で括らないといけないので、
/xxx#{Regexp.alt *rs}xxx/ は
/xxx(?:#{rs.join('|')})xxx/ に比べて短くなり、記号が減って読みやすくな
る(と思う)こともあわせれば、それなりに使いやすくなっていると思います。
-- 
[田中 哲][たなか あきら][Tanaka Akira]

In This Thread

Prev Next