Bardzo pomocne okazało się też wyjaśnienie Gary'ego Wrighta.
http://www.ruby-forum.com/topic/1393096#990065
Odpowiedź Gary'ego Wrighta brzmi -
http://www.ruby-doc.org/core/classes/Array.html
Dokumenty z pewnością mogłyby być bardziej jasne, ale faktyczne zachowanie jest spójne i przydatne. Uwaga: zakładam, że wersja String.X. 1.9.X.
Pomaga rozważyć numerację w następujący sposób:
-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
Częstym (i zrozumiałym) błędem jest zbyt duże założenie, że semantyka indeksu pojedynczego argumentu jest taka sama jak semantyka
pierwszego argumentu w scenariuszu (lub zakresie) dwóch argumentów. W praktyce to nie to samo, a dokumentacja tego nie odzwierciedla. Błąd jest jednak zdecydowanie w dokumentacji, a nie w implementacji:
pojedynczy argument: indeks reprezentuje pozycję pojedynczego znaku w ciągu. Wynikiem jest albo pojedynczy ciąg znaków znaleziony w indeksie, albo zero, ponieważ w danym indeksie nie ma znaku.
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
dwa argumenty całkowite: argumenty identyfikują część ciągu do wyodrębnienia lub zamiany. W szczególności można również zidentyfikować części łańcucha o zerowej szerokości, dzięki czemu tekst można wstawić przed lub po istniejących znakach, w tym na początku lub na końcu łańcucha. W takim przypadku pierwszy argument nie identyfikuje pozycji znaku, ale zamiast tego określa odstęp między znakami, jak pokazano na powyższym schemacie. Drugi argument to długość, która może wynosić 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"
Zachowanie zakresu jest dość interesujące. Punkt początkowy jest taki sam jak pierwszy argument, gdy podano dwa argumenty (jak opisano powyżej), ale punktem końcowym zakresu może być „pozycja znaku” jak w przypadku pojedynczego indeksowania lub „pozycja krawędzi” jak w przypadku dwóch argumentów liczb całkowitych. Różnica zależy od tego, czy stosowany jest zakres podwójnych kropek, czy potrójny:
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.
Jeśli wrócisz do tych przykładów i nalegasz na użycie semantyki pojedynczego indeksu dla przykładów indeksowania podwójnego lub zakresu, po prostu się pomylisz. Musisz użyć alternatywnej numeracji, którą pokazuję na schemacie ascii, aby modelować rzeczywiste zachowanie.