También encontré muy útil la explicación de Gary Wright.
http://www.ruby-forum.com/topic/1393096#990065
La respuesta de Gary Wright es:
http://www.ruby-doc.org/core/classes/Array.html
Los documentos ciertamente podrían ser más claros, pero el comportamiento real es coherente y útil. Nota: estoy asumiendo la versión 1.9.X de String.
Ayuda a considerar la numeración de la siguiente manera:
-4 -3 -2 -1 <-- numbering for single argument indexing
0 1 2 3
+---+---+---+---+
| a | b | c | d |
+---+---+---+---+
0 1 2 3 4 <-- numbering for two argument indexing or start of range
-4 -3 -2 -1
El error común (y comprensible) es también asumir que la semántica del índice de argumento único es la misma que la semántica del
primer argumento en el escenario (o rango) de dos argumentos. No son lo mismo en la práctica y la documentación no refleja esto. Sin embargo, el error definitivamente está en la documentación y no en la implementación:
argumento único: el índice representa una posición de un solo carácter dentro de la cadena. El resultado es la cadena de un solo carácter que se encuentra en el índice o nula porque no hay ningún carácter en el índice dado.
s = ""
s[0] # nil because no character at that position
s = "abcd"
s[0] # "a"
s[-4] # "a"
s[-5] # nil, no characters before the first one
dos argumentos enteros: los argumentos identifican una porción de la cadena para extraer o reemplazar. En particular, las partes de la cadena de ancho cero también se pueden identificar para que el texto se pueda insertar antes o después de los caracteres existentes, incluso en el frente o al final de la cadena. En este caso, el primer argumento no identifica una posición de carácter, sino que identifica el espacio entre caracteres como se muestra en el diagrama anterior. El segundo argumento es la longitud, que puede ser 0.
s = "abcd" # each example below assumes s is reset to "abcd"
To insert text before 'a': s[0,0] = "X" # "Xabcd"
To insert text after 'd': s[4,0] = "Z" # "abcdZ"
To replace first two characters: s[0,2] = "AB" # "ABcd"
To replace last two characters: s[-2,2] = "CD" # "abCD"
To replace middle two characters: s[1..3] = "XX" # "aXXd"
El comportamiento de un rango es bastante interesante. El punto de partida es el mismo que el primer argumento cuando se proporcionan dos argumentos (como se describió anteriormente), pero el punto final del rango puede ser la 'posición de caracteres' como con indexación simple o la "posición de borde" como con dos argumentos enteros. La diferencia está determinada por si se utiliza el rango de punto doble o el rango de punto triple:
s = "abcd"
s[1..1] # "b"
s[1..1] = "X" # "aXcd"
s[1...1] # ""
s[1...1] = "X" # "aXbcd", the range specifies a zero-width portion of
the string
s[1..3] # "bcd"
s[1..3] = "X" # "aX", positions 1, 2, and 3 are replaced.
s[1...3] # "bc"
s[1...3] = "X" # "aXd", positions 1, 2, but not quite 3 are replaced.
Si revisa estos ejemplos e insiste y usa la semántica de índice único para los ejemplos de indexación doble o de rango, se confundirá. Tienes que usar la numeración alternativa que muestro en el diagrama ASCII para modelar el comportamiento real.