[ruby-trunk - Bug #6195][Open] String#[] に逆順の Range を渡した場合の挙動

Issue #6195 has been reported by mrkn (Kenta M.).


Bug #6195: String#[] に逆順の Range を渡した場合の挙動

Author: mrkn (Kenta M.)
Status: Open
Priority: Normal
Assignee: matz (Yukihiro M.)
Category: core
Target version: 2.0.0
ruby -v: ruby 2.0.0dev (2012-03-23 trunk 35121) [x86_64-darwin11.3.0]

以下のように String#[] に対して、範囲の開始インデックスが文字列の長さ以下の値である逆順の Range (beg > end)
を渡した場合に空文字列が返ります。

“1”[1…0] #=> “”
“1”[1…-1] #=> “”
“123”[2…1] #=> “”
“123”[2…-2] #=> “”

一方、範囲の開始インデックスが文字列の長さより大きい場合は nil が返ります。

“1”[2…0] #=> nil
“1”[2…-1] #=> nil
“123”[4…1] #=> nil
“123”[4…-2] #=> nil

この挙動の違いは、rb_range_beg_len の実装に起因しています。
文字列のインデックスが昇順のみである仕様を考慮すると、上記前者の場合も nil が返るべきじゃないかと思います。

Issue #6195 has been updated by mame (Yusuke E.).

Status changed from Open to Assigned


Bug #6195: String#[] に逆順の Range を渡した場合の挙動

Author: mrkn (Kenta M.)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro M.)
Category: core
Target version: 2.0.0
ruby -v: ruby 2.0.0dev (2012-03-23 trunk 35121) [x86_64-darwin11.3.0]

以下のように String#[] に対して、範囲の開始インデックスが文字列の長さ以下の値である逆順の Range (beg > end)
を渡した場合に空文字列が返ります。

“1”[1…0] #=> “”
“1”[1…-1] #=> “”
“123”[2…1] #=> “”
“123”[2…-2] #=> “”

一方、範囲の開始インデックスが文字列の長さより大きい場合は nil が返ります。

“1”[2…0] #=> nil
“1”[2…-1] #=> nil
“123”[4…1] #=> nil
“123”[4…-2] #=> nil

この挙動の違いは、rb_range_beg_len の実装に起因しています。
文字列のインデックスが昇順のみである仕様を考慮すると、上記前者の場合も nil が返るべきじゃないかと思います。

Issue #6195 has been updated by shugo (Shugo M.).

前田です。

mrkn (Kenta M.) wrote:

“1”[2…-1] #=> nil
“123”[4…1] #=> nil
“123”[4…-2] #=> nil

この挙動の違いは、rb_range_beg_len の実装に起因しています。
文字列のインデックスが昇順のみである仕様を考慮すると、上記前者の場合も nil が返るべきじゃないかと思います。

私も最初そう思ったのですが、PythonやJavaScriptではどちらの場合も空文字列を返すようです。

以下の例はどちらもRubyのs[x…y]相当(s[x…y]ではない)です。

defiant:ruby$ python
Python 2.7.2+ (default, Oct 4 2011, 20:03:08)
[GCC 4.6.1] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.

“abc”[1:2]
‘b’
“abc”[1:1]
‘’
“abc”[1:0]
‘’
“abc”[4:0]
‘’
defiant:ruby$ js
“abc”.slice(1,2)
‘b’
“abc”.slice(1,1)
‘’
“abc”.slice(1,0)
‘’
“abc”.slice(4,0)
‘’

これはこれで合理的だと思いますがどうでしょうか。

また、Net::FTP#parse227が今の挙動に依存しているようです。

def parse227(resp) # :nodoc:
  if resp[0, 3] != "227"
    raise FTPReplyError, resp
  end
  left = resp.index("(")
  right = resp.index(")")
  if left == nil or right == nil
    raise FTPProtoError, resp
  end
  numbers = resp[left + 1 .. right - 1].split(",")
  if numbers.length != 6
    raise FTPProtoError, resp
  end
  host = numbers[0, 4].join(".")
  port = (numbers[4].to_i << 8) + numbers[5].to_i
  return host, port
end

respが"227 )(“のようなケースでも今のString#[]ではresp[left + 1 … right - 1]
が”“になるのでsplitできますが、nilを返すようになるとnil.split(”,")でNoMethodError
になってしまいます。
このコードがひどいと言われればそれまでですが、若気の至りということで。

たぶん当時のftplib.pyのパクリなんだろうなあ。


Bug #6195: String#[] に逆順の Range を渡した場合の挙動

Author: mrkn (Kenta M.)
Status: Open
Priority: Normal
Assignee: matz (Yukihiro M.)
Category: core
Target version: 2.0.0
ruby -v: ruby 2.0.0dev (2012-03-23 trunk 35121) [x86_64-darwin11.3.0]

以下のように String#[] に対して、範囲の開始インデックスが文字列の長さ以下の値である逆順の Range (beg > end)
を渡した場合に空文字列が返ります。

“1”[1…0] #=> “”
“1”[1…-1] #=> “”
“123”[2…1] #=> “”
“123”[2…-2] #=> “”

一方、範囲の開始インデックスが文字列の長さより大きい場合は nil が返ります。

“1”[2…0] #=> nil
“1”[2…-1] #=> nil
“123”[4…1] #=> nil
“123”[4…-2] #=> nil

この挙動の違いは、rb_range_beg_len の実装に起因しています。
文字列のインデックスが昇順のみである仕様を考慮すると、上記前者の場合も nil が返るべきじゃないかと思います。

Issue #6195 has been updated by knu (Akinori MUSHA).

文字列のスライスが(Rangeの始点さえ範囲内なら)nilを返さないという現仕様は利便性にフォーカスしていて合理的だと思っています。

たとえば、

if s.start_with?(prefix)
  logger.info "message body is " + s[prefix.length..-1]
end

のようなコードは私の手元にもたくさんありますし、Rubyのソースツリーで grep -rF …-1 lib
して眺めただけでもnilを期待していない所はいくつもあるようです。

Bug #6195: String#[] に逆順の Range を渡した場合の挙動

Author: mrkn (Kenta M.)
Status: Assigned
Priority: Normal
Assignee: matz (Yukihiro M.)
Category: core
Target version: 2.0.0
ruby -v: ruby 2.0.0dev (2012-03-23 trunk 35121) [x86_64-darwin11.3.0]

以下のように String#[] に対して、範囲の開始インデックスが文字列の長さ以下の値である逆順の Range (beg > end)
を渡した場合に空文字列が返ります。

“1”[1…0] #=> “”
“1”[1…-1] #=> “”
“123”[2…1] #=> “”
“123”[2…-2] #=> “”

一方、範囲の開始インデックスが文字列の長さより大きい場合は nil が返ります。

“1”[2…0] #=> nil
“1”[2…-1] #=> nil
“123”[4…1] #=> nil
“123”[4…-2] #=> nil

この挙動の違いは、rb_range_beg_len の実装に起因しています。
文字列のインデックスが昇順のみである仕様を考慮すると、上記前者の場合も nil が返るべきじゃないかと思います。

Issue #6195 has been updated by matz (Yukihiro M.).

Status changed from Assigned to Rejected

本人も取り下げたようなのでリジェクトします。

Matz.


Bug #6195: String#[] に逆順の Range を渡した場合の挙動

Author: mrkn (Kenta M.)
Status: Rejected
Priority: Normal
Assignee: matz (Yukihiro M.)
Category: core
Target version: 2.0.0
ruby -v: ruby 2.0.0dev (2012-03-23 trunk 35121) [x86_64-darwin11.3.0]

以下のように String#[] に対して、範囲の開始インデックスが文字列の長さ以下の値である逆順の Range (beg > end)
を渡した場合に空文字列が返ります。

“1”[1…0] #=> “”
“1”[1…-1] #=> “”
“123”[2…1] #=> “”
“123”[2…-2] #=> “”

一方、範囲の開始インデックスが文字列の長さより大きい場合は nil が返ります。

“1”[2…0] #=> nil
“1”[2…-1] #=> nil
“123”[4…1] #=> nil
“123”[4…-2] #=> nil

この挙動の違いは、rb_range_beg_len の実装に起因しています。
文字列のインデックスが昇順のみである仕様を考慮すると、上記前者の場合も nil が返るべきじゃないかと思います。