|
View:
New views
5 Messages
—
Rating Filter:
Alert me
|
|
|
[ruby-dev:39604] [Bug #2323] "Z".."Z".succが空Bug #2323: "Z".."Z".succが空
http://redmine.ruby-lang.org/issues/show/2323 起票者: Hiro Asari ステータス: Open, 優先度: Normal カテゴリ: core ruby -v: ruby 1.9.2dev (2009-11-02 trunk 25625) [x86_64-darwin10.0.0] surfboard:~$ ruby1.9 -v; ruby1.9 -e 'p ("Z".."Z".succ); p ("Z".."Z".succ).to_a' ruby 1.9.2dev (2009-11-02 trunk 25625) [x86_64-darwin10.0.0] "Z".."AA" [] "Z".succではなくてもうちょっと”離れた”ヤツをRangeの終わりとして指定すると"AA"はしっかりと入っています。 surfboard:~$ ruby1.9 -e 'p ("Z".."ZA").include? "Z".succ' true でも半端な”離れ”方ではいけません。 surfboard:~$ ruby1.9 -e 'p ("Z".."CA").include? "Z".succ' false to_aを介しても同様です。 surfboard:~$ ruby1.9 -e 'p ("Z".."ZA").to_a.include? "Z".succ' true surfboard:~$ ruby1.9 -e 'p ("Z".."CA").to_a.include? "Z".succ' false ---------------------------------------- http://redmine.ruby-lang.org |
|
|
[ruby-dev:39612] Re: [Bug #2323] "Z".."Z".succが空なかだです。
At Mon, 2 Nov 2009 16:19:40 +0900, Hiro Asari wrote in [ruby-dev:39604]: > surfboard:~$ ruby1.9 -v; ruby1.9 -e 'p ("Z".."Z".succ); p ("Z".."Z".succ).to_a' > ruby 1.9.2dev (2009-11-02 trunk 25625) [x86_64-darwin10.0.0] > "Z".."AA" > [] こんなところでしょうか。 Index: string.c =================================================================== --- string.c (revision 25629) +++ string.c (working copy) @@ -2844,4 +2844,44 @@ rb_str_succ_bang(VALUE str) } +static int +str_succ_cmp(VALUE str1, VALUE str2, rb_encoding *enc) +{ + const char *p1 = RSTRING_PTR(str1), *e1 = RSTRING_END(str1); + const char *p2 = RSTRING_PTR(str2), *e2 = RSTRING_END(str2); + size_t l1, l2; + do { + if (ISUPPER(*p1) && ISUPPER(*p2)) { + for (l1 = 1; p1+l1 < e1 && ISUPPER(p1[l1]); l1++); + for (l2 = 1; p2+l2 < e2 && ISUPPER(p2[l2]); l2++); + } + else if (ISLOWER(*p1) && ISLOWER(*p2)) { + for (l1 = 1; p1+l1 < e1 && ISLOWER(p1[l1]); l1++); + for (l2 = 1; p2+l2 < e2 && ISLOWER(p2[l2]); l2++); + } + else if (ISDIGIT(*p1) && ISDIGIT(*p2)) { + for (l1 = 1; p1+l1 < e1 && ISDIGIT(p1[l1]); l1++); + for (l2 = 1; p2+l2 < e2 && ISDIGIT(p2[l2]); l2++); + } + else { + int n, c; + for (l1 = 0; p1+l1 < e1; l1 += n) { + c = rb_enc_ascget(p1+l1, e1, &n, enc); + if (ISALNUM(c)) break; + } + for (l2 = 0; p2+l2 < e2; l2 += n) { + c = rb_enc_ascget(p2+l2, e2, &n, enc); + if (ISALNUM(c)) break; + } + if (l1 == 0 || l2 == 0) return 1; + } + if (l1 > l2) return 1; + if (l1 == l2) { + if (memcmp(p1, p2, l1) > 0) return 0; + } + p1 += l1; + p2 += l2; + } while (p1 < e1 || p2 < e2); + return -(p1 == e1 && p2 == e2); +} /* @@ -2881,4 +2921,5 @@ rb_str_upto(int argc, VALUE *argv, VALUE ID succ; int n, excl, ascii; + char c, e; rb_encoding *enc; @@ -2891,8 +2932,9 @@ rb_str_upto(int argc, VALUE *argv, VALUE ascii = (is_ascii_string(beg) && is_ascii_string(end)); /* single character */ - if (RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && ascii) { - char c = RSTRING_PTR(beg)[0]; - char e = RSTRING_PTR(end)[0]; - + if (ascii && + RSTRING_LEN(beg) == 1 && RSTRING_LEN(end) == 1 && + (c = RSTRING_PTR(beg)[0], ISALPHA(c)) && + (e = RSTRING_PTR(end)[0], ISALPHA(e)) && + (ISUPPER(c) == ISUPPER(e))) { if (c > e || (excl && c == e)) return beg; for (;;) { @@ -2906,5 +2948,5 @@ rb_str_upto(int argc, VALUE *argv, VALUE /* both edges are all digits */ if (ascii && ISDIGIT(RSTRING_PTR(beg)[0]) && ISDIGIT(RSTRING_PTR(end)[0])) { - char *s, *send; + const char *s, *send; VALUE b, e; int width; @@ -2949,5 +2991,8 @@ rb_str_upto(int argc, VALUE *argv, VALUE /* normal case */ no_digits: - n = rb_str_cmp(beg, end); + if (ascii && rb_enc_str_coderange(beg) == rb_enc_str_coderange(end)) + n = str_succ_cmp(beg, end, enc); + else + n = rb_str_cmp(beg, end); if (n > 0 || (excl && n == 0)) return beg; Index: test/ruby/test_range.rb =================================================================== --- test/ruby/test_range.rb (revision 25629) +++ test/ruby/test_range.rb (working copy) @@ -256,4 +256,7 @@ class TestRange < Test::Unit::TestCase assert(!(("a"..."z").include?("z"))) assert(!(("a".."z").include?("cc"))) + assert(("Z".."ZA").include?("AA")) + assert(!("Z".."za").include?("AA")) + assert(("Z".."CA").include?("AA")) assert((0...10).include?(5)) end Index: test/ruby/test_string.rb =================================================================== --- test/ruby/test_string.rb (revision 25629) +++ test/ruby/test_string.rb (working copy) @@ -1588,4 +1588,8 @@ class TestString < Test::Unit::TestCase }) assert_equal(676, count) + + a = [] + S("Z").upto(S("AA")) {|s| a << s} + assert_equal([S("Z"), S("AA")], a) end -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦 |
|
|
[ruby-dev:39622] Re: [Bug #2323] "Z".."Z".succが空浅里です。
2009/11/2 Nobuyoshi Nakada <nobu@...>: > なかだです。 > > At Mon, 2 Nov 2009 16:19:40 +0900, > Hiro Asari wrote in [ruby-dev:39604]: >> surfboard:~$ ruby1.9 -v; ruby1.9 -e 'p ("Z".."Z".succ); p ("Z".."Z".succ).to_a' >> ruby 1.9.2dev (2009-11-02 trunk 25625) [x86_64-darwin10.0.0] >> "Z".."AA" >> [] > > こんなところでしょうか。 このパッチで件の問題は解決されていますが、ちょっと別なところで問題になるかもしれません。 このパッチを当ててみたところ、"Z".."a"は空です。1.8では["Z"]が返ってきます。 更に、 http://redmine.ruby-lang.org/issues/show/1891にあるように、 パッチ無しでは["Z", "[", "\\", "]", "^", "_", "`", "a"]です。 これに対応したリビジョン(r24573)では加えて:Z..:aが認められていて、 それにはアスキー配列に則ったシンボルが含まれています。 個人的には"Z".succが"AA"であるならば、二つ以上の要素を持つ"Z"から始まるRangeは"AA"を含むべきだと考えます。 Rangeを半順序集合に定義するのも可能とは思いますが、特別な動きをする事があるのならば、 それは明確に書かれていないと混乱を招くと思います。 参考までに指摘しておきます。 -- Hirotsugu Asari |
|
|
[ruby-dev:39630] Re: [Bug #2323] "Z".."Z".succが空まつもと ゆきひろです
In message "Re: [ruby-dev:39622] Re: [Bug #2323] "Z".."Z".succが空" on Tue, 3 Nov 2009 22:22:58 +0900, Hiro Asari <asari.ruby@...> writes: |個人的には"Z".succが"AA"であるならば、二つ以上の要素を持つ"Z"から始まるRangeは"AA"を含むべきだと考えます。 |Rangeを半順序集合に定義するのも可能とは思いますが、特別な動きをする事があるのならば、 |それは明確に書かれていないと混乱を招くと思います。 文字列のRangeについては、 * 文字列の順序の定義が複数ある(辞書順とsuccによるもの) * Rangeはsuccを使うが、これは半順序集合でいろいろ面倒 という事情があります。で、現在、ちょっと中途半端な状態になっ てます。最終的な仕様を検討する時間(とやる気)が取れなくて。 現状 * 両端ともすべてASCII数字である場合には、数的な順序 * 両端ともASCII1文字である場合には、ASCII文字コード的な順序 になってます。で、このいずれにもあてはまらないケースの仕様は 正直確定してません。苦労してもあんまり使われなさそうだし。 ただ、 * 両端が共通の先頭部分を持ち、非共通部分がすべてASCII数字で ある場合には数的な順序 というのは採用しようと思ってます。あとは、ある文字列から別の 文字列にsuccの連鎖で到達できるかどうか簡易に判定できるのであ れば、それに従って順序を処理すると良いと思うのですけど、でき るんだっけか。 まつもと ゆきひろ /:|) |
|
|
[ruby-dev:39631] Re: [Bug #2323] "Z".."Z".succが空成瀬です。
Yukihiro Matsumoto wrote: > まつもと ゆきひろです > > In message "Re: [ruby-dev:39622] Re: [Bug #2323] "Z".."Z".succが空" > on Tue, 3 Nov 2009 22:22:58 +0900, Hiro Asari <asari.ruby@...> writes: > > > |個人的には"Z".succが"AA"であるならば、二つ以上の要素を持つ"Z"から始まるRangeは"AA"を含むべきだと考えます。 > |Rangeを半順序集合に定義するのも可能とは思いますが、特別な動きをする事があるのならば、 > |それは明確に書かれていないと混乱を招くと思います。 > > 文字列のRangeについては、 > > * 文字列の順序の定義が複数ある(辞書順とsuccによるもの) > * Rangeはsuccを使うが、これは半順序集合でいろいろ面倒 > > という事情があります。で、現在、ちょっと中途半端な状態になっ > てます。最終的な仕様を検討する時間(とやる気)が取れなくて。 > > 現状 > > * 両端ともすべてASCII数字である場合には、数的な順序 > * 両端ともASCII1文字である場合には、ASCII文字コード的な順序 > > になってます。で、このいずれにもあてはまらないケースの仕様は > 正直確定してません。苦労してもあんまり使われなさそうだし。 念のため補足しておきますと、 Range#each のマニュアルには succ を用いると書いてありますが、 String や Symbol の場合は実際には upto を呼んでおり、 String#upto は常には String#succ を呼んでいません。 上記のまつもとさんの説明は String#upto の説明になります。 言い換えると、Range#to_a から Range#eachが呼ばれ、 range_each 経由で String#upto に行っているので、 この問題は以下のように書き換えることが出来ます。 % ruby19 -ve'"Z".upto("AA"){|x|p x}' ruby 1.9.2dev (2009-11-02 trunk 25632) [x86_64-freebsd8.0] > あとは、ある文字列から別の > 文字列にsuccの連鎖で到達できるかどうか簡易に判定できるのであ > れば、それに従って順序を処理すると良いと思うのですけど、でき > るんだっけか。 ちょっと簡易とは言いづらい気がします。 先の中田さんのパッチだと "0 0" から到達できない "0 00" に対して、 upto が微妙に動いたりしています。 "0 0".upto("0 00"){|x|p x} 英数の間に非英数がはさまったり、非英数が繰り上がって英数に突入するケースは なかなか難しいように思います。 一度きっちり考えて文書化しさえすれば、あとは実装するだけではありますが。 代替案として、常に succ を使うようにして、なんとなく動くようにしつつ、 とりあえず確実に停止するようにするという方法もありますかね。 中田さんのパッチはそのような趣旨であるようにみえます。 -- NARUSE, Yui <naruse@...> |
| Free embeddable forum powered by Nabble | Forum Help |