[DOC] String slices doc (#14740)

This commit is contained in:
Burdette Lamar 2025-10-10 15:39:05 -05:00 committed by GitHub
parent 0a6cd03b3d
commit 0090311db2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2025-10-10 20:39:35 +00:00
Merged-By: peterzhu2118 <peter@peterzhu.ca>
4 changed files with 298 additions and 173 deletions

View File

@ -159,146 +159,6 @@
# - #rstrip, #rstrip!: Strip trailing whitespace.
# - #strip, #strip!: Strip leading and trailing whitespace.
#
# == +String+ Slices
#
# A _slice_ of a string is a substring selected by certain criteria.
#
# These instance methods utilize slicing:
#
# - String#[] (aliased as String#slice): Returns a slice copied from +self+.
# - String#[]=: Mutates +self+ with the slice replaced.
# - String#slice!: Mutates +self+ with the slice removed and returns the removed slice.
#
# Each of the above methods takes arguments that determine the slice
# to be copied or replaced.
#
# The arguments have several forms.
# For a string +string+, the forms are:
#
# - <tt>string[index]</tt>
# - <tt>string[start, length]</tt>
# - <tt>string[range]</tt>
# - <tt>string[regexp, capture = 0]</tt>
# - <tt>string[substring]</tt>
#
# <b><tt>string[index]</tt></b>
#
# When a non-negative integer argument +index+ is given,
# the slice is the 1-character substring found in +self+ at character offset +index+:
#
# 'bar'[0] # => "b"
# 'bar'[2] # => "r"
# 'bar'[20] # => nil
# 'тест'[2] # => "с"
# 'こんにちは'[4] # => "は"
#
# When a negative integer +index+ is given,
# the slice begins at the offset given by counting backward from the end of +self+:
#
# 'bar'[-3] # => "b"
# 'bar'[-1] # => "r"
# 'bar'[-20] # => nil
#
# <b><tt>string[start, length]</tt></b>
#
# When non-negative integer arguments +start+ and +length+ are given,
# the slice begins at character offset +start+, if it exists,
# and continues for +length+ characters, if available:
#
# 'foo'[0, 2] # => "fo"
# 'тест'[1, 2] # => "ес"
# 'こんにちは'[2, 2] # => "にち"
# # Zero length.
# 'foo'[2, 0] # => ""
# # Length not entirely available.
# 'foo'[1, 200] # => "oo"
# # Start out of range.
# 'foo'[4, 2] # => nil
#
# Special case: if +start+ equals the length of +self+,
# the slice is a new empty string:
#
# 'foo'[3, 2] # => ""
# 'foo'[3, 200] # => ""
#
# When a negative +start+ and non-negative +length+ are given,
# the slice begins by counting backward from the end of +self+,
# and continues for +length+ characters, if available:
#
# 'foo'[-2, 2] # => "oo"
# 'foo'[-2, 200] # => "oo"
# # Start out of range.
# 'foo'[-4, 2] # => nil
#
# When a negative +length+ is given, there is no slice:
#
# 'foo'[1, -1] # => nil
# 'foo'[-2, -1] # => nil
#
# <b><tt>string[range]</tt></b>
#
# When a Range argument +range+ is given,
# it creates a substring of +string+ using the indices in +range+.
# The slice is then determined as above:
#
# 'foo'[0..1] # => "fo"
# 'foo'[0, 2] # => "fo"
#
# 'foo'[2...2] # => ""
# 'foo'[2, 0] # => ""
#
# 'foo'[1..200] # => "oo"
# 'foo'[1, 200] # => "oo"
#
# 'foo'[4..5] # => nil
# 'foo'[4, 2] # => nil
#
# 'foo'[-4..-3] # => nil
# 'foo'[-4, 2] # => nil
#
# 'foo'[3..4] # => ""
# 'foo'[3, 2] # => ""
#
# 'foo'[-2..-1] # => "oo"
# 'foo'[-2, 2] # => "oo"
#
# 'foo'[-2..197] # => "oo"
# 'foo'[-2, 200] # => "oo"
#
# <b><tt>string[regexp, capture = 0]</tt></b>
#
# When the Regexp argument +regexp+ is given,
# and the +capture+ argument is <tt>0</tt>,
# the slice is the first matching substring found in +self+:
#
# 'foo'[/o/] # => "o"
# 'foo'[/x/] # => nil
# s = 'hello there'
# s[/[aeiou](.)\1/] # => "ell"
# s[/[aeiou](.)\1/, 0] # => "ell"
#
# If the argument +capture+ is provided and not <tt>0</tt>,
# it should be either a capture group index (integer)
# or a capture group name (String or Symbol);
# the slice is the specified capture
# (see {Groups and Captures}[rdoc-ref:Regexp@Groups+and+Captures]):
#
# s = 'hello there'
# s[/[aeiou](.)\1/, 1] # => "l"
# s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, "non_vowel"] # => "l"
# s[/(?<vowel>[aeiou])(?<non_vowel>[^aeiou])/, :vowel] # => "e"
#
# If an invalid capture group index is given, there is no slice.
# If an invalid capture group name is given, +IndexError+ is raised.
#
# <b><tt>string[substring]</tt></b>
#
# When the single +String+ argument +substring+ is given,
# it returns the substring from +self+ if found, otherwise +nil+:
#
# 'foo'['oo'] # => "oo"
# 'foo'['xx'] # => nil
#
# == What's Here
#
# First, what's elsewhere. Class +String+:

98
doc/string/aref.rdoc Normal file
View File

@ -0,0 +1,98 @@
Returns the substring of +self+ specified by the arguments.
<b>Form <tt>self[index]</tt></b>
With non-negative integer argument +index+ given,
returns the 1-character substring found in self at character offset index:
'hello'[0] # => "h"
'hello'[4] # => "o"
'hello'[5] # => nil
'тест'[2] # => "с"
'こんにちは'[4] # => "は"
With negative integer argument +index+ given,
counts backward from the end of +self+:
'hello'[-1] # => "o"
'hello'[-5] # => "h"
'hello'[-6] # => nil
<b>Form <tt>self[start, length]</tt></b>
With integer arguments +start+ and +length+ given,
returns a substring of size +length+ characters (as available)
beginning at character offset specified by +start+.
If argument +start+ is non-negative,
the offset is +start+:
'hello'[0, 1] # => "h"
'hello'[0, 5] # => "hello"
'hello'[0, 6] # => "hello"
'hello'[2, 3] # => "llo"
'hello'[2, 0] # => ""
'hello'[2, -1] # => nil
If argument +start+ is negative,
counts backward from the end of +self+:
'hello'[-1, 1] # => "o"
'hello'[-5, 5] # => "hello"
'hello'[-1, 0] # => ""
'hello'[-6, 5] # => nil
Special case: if +start+ equals the length of +self+,
returns a new empty string:
'hello'[5, 3] # => ""
<b>Form <tt>self[range]</tt></b>
With Range argument +range+ given,
forms substring <tt>self[range.start, range.size]</tt>:
'hello'[0..2] # => "hel"
'hello'[0, 3] # => "hel"
'hello'[0...2] # => "he"
'hello'[0, 2] # => "he"
'hello'[0, 0] # => ""
'hello'[0...0] # => ""
<b>Form <tt>self[regexp, capture = 0]</tt></b>
With Regexp argument +regexp+ given and +capture+ as zero,
searches for a matching substring in +self+;
updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
'hello'[/ell/] # => "ell"
'hello'[/l+/] # => "ll"
'hello'[//] # => ""
'hello'[/nosuch/] # => nil
With +capture+ as a positive integer +n+,
returns the +n+th matched group:
'hello'[/(h)(e)(l+)(o)/] # => "hello"
'hello'[/(h)(e)(l+)(o)/, 1] # => "h"
$1 # => "h"
'hello'[/(h)(e)(l+)(o)/, 2] # => "e"
$2 # => "e"
'hello'[/(h)(e)(l+)(o)/, 3] # => "ll"
'hello'[/(h)(e)(l+)(o)/, 4] # => "o"
'hello'[/(h)(e)(l+)(o)/, 5] # => nil
<b>Form <tt>self[substring]</tt></b>
With string argument +substring+ given,
returns the matching substring of +self+, if found:
'hello'['ell'] # => "ell"
'hello'[''] # => ""
'hello'['nosuch'] # => nil
'тест'['ес'] # => "ес"
'こんにちは'['んにち'] # => "んにち"
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].

183
doc/string/aset.rdoc Normal file
View File

@ -0,0 +1,183 @@
Returns +self+ with all, a substring, or none of its contents replaced;
returns the argument +other_string+.
<b>Form <tt>self[index] = other_string</tt></b>
With non-negative integer argument +index+ given,
searches for the 1-character substring found in self at character offset index:
s = 'hello'
s[0] = 'foo' # => "foo"
s # => "fooello"
s = 'hello'
s[4] = 'foo' # => "foo"
s # => "hellfoo"
s = 'hello'
s[5] = 'foo' # => "foo"
s # => "hellofoo"
s = 'hello'
s[6] = 'foo' # Raises IndexError: index 6 out of string.
With negative integer argument +index+ given,
counts backward from the end of +self+:
s = 'hello'
s[-1] = 'foo' # => "foo"
s # => "hellfoo"
s = 'hello'
s[-5] = 'foo' # => "foo"
s # => "fooello"
s = 'hello'
s[-6] = 'foo' # Raises IndexError: index -6 out of string.
<b>Form <tt>self[start, length] = other_string</tt></b>
With integer arguments +start+ and +length+ given,
searches for a substring of size +length+ characters (as available)
beginning at character offset specified by +start+.
If argument +start+ is non-negative,
the offset is +start':
s = 'hello'
s[0, 1] = 'foo' # => "foo"
s # => "fooello"
s = 'hello'
s[0, 5] = 'foo' # => "foo"
s # => "foo"
s = 'hello'
s[0, 9] = 'foo' # => "foo"
s # => "foo"
s = 'hello'
s[2, 0] = 'foo' # => "foo"
s # => "hefoollo"
s = 'hello'
s[2, -1] = 'foo' # Raises IndexError: negative length -1.
If argument +start+ is negative,
counts backward from the end of +self+:
s = 'hello'
s[-1, 1] = 'foo' # => "foo"
s # => "hellfoo"
s = 'hello'
s[-1, 9] = 'foo' # => "foo"
s # => "hellfoo"
s = 'hello'
s[-5, 2] = 'foo' # => "foo"
s # => "foollo"
s = 'hello'
s[-3, 0] = 'foo' # => "foo"
s # => "hefoollo"
s = 'hello'
s[-6, 2] = 'foo' # Raises IndexError: index -6 out of string.
Special case: if +start+ equals the length of +self+,
the argument is appended to +self+:
s = 'hello'
s[5, 3] = 'foo' # => "foo"
s # => "hellofoo"
<b>Form <tt>self[range] = other_string</tt></b>
With Range argument +range+ given,
equivalent to <tt>self[range.start, range.size] = other_string</tt>:
s0 = 'hello'
s1 = 'hello'
s0[0..2] = 'foo' # => "foo"
s1[0, 3] = 'foo' # => "foo"
s0 # => "foolo"
s1 # => "foolo"
s = 'hello'
s[0...2] = 'foo' # => "foo"
s # => "foollo"
s = 'hello'
s[0...0] = 'foo' # => "foo"
s # => "foohello"
s = 'hello'
s[9..10] = 'foo' # Raises RangeError: 9..10 out of range
<b>Form <tt>self[regexp, capture = 0] = other_string</tt></b>
With Regexp argument +regexp+ given and +capture+ as zero,
searches for a matching substring in +self+;
updates {Regexp-related global variables}[rdoc-ref:Regexp@Global+Variables]:
s = 'hello'
s[/l/] = 'L' # => "L"
[$`, $&, $'] # => ["he", "l", "lo"]
s[/eLlo/] = 'owdy' # => "owdy"
[$`, $&, $'] # => ["h", "eLlo", ""]
s[/eLlo/] = 'owdy' # Raises IndexError: regexp not matched.
[$`, $&, $'] # => [nil, nil, nil]
With +capture+ as a positive integer +n+,
searches for the +n+th matched group:
s = 'hello'
s[/(h)(e)(l+)(o)/] = 'foo' # => "foo"
[$`, $&, $'] # => ["", "hello", ""]
s = 'hello'
s[/(h)(e)(l+)(o)/, 1] = 'foo' # => "foo"
s # => "fooello"
[$`, $&, $'] # => ["", "hello", ""]
s = 'hello'
s[/(h)(e)(l+)(o)/, 2] = 'foo' # => "foo"
s # => "hfoollo"
[$`, $&, $'] # => ["", "hello", ""]
s = 'hello'
s[/(h)(e)(l+)(o)/, 4] = 'foo' # => "foo"
s # => "hellfoo"
[$`, $&, $'] # => ["", "hello", ""]
s = 'hello'
# => "hello"
s[/(h)(e)(l+)(o)/, 5] = 'foo # Raises IndexError: index 5 out of regexp.
s = 'hello'
s[/nosuch/] = 'foo' # Raises IndexError: regexp not matched.
<b>Form <tt>self[substring] = other_string</tt></b>
With string argument +substring+ given:
s = 'hello'
s['l'] = 'foo' # => "foo"
s # => "hefoolo"
s = 'hello'
s['ll'] = 'foo' # => "foo"
s # => "hefooo"
s = 'тест'
s['ес'] = 'foo' # => "foo"
s # => "тfooт"
s = 'こんにちは'
s['んにち'] = 'foo' # => "foo"
s # => "こfooは"
s['nosuch'] = 'foo' # Raises IndexError: string not matched.
Related: see {Modifying}[rdoc-ref:String@Modifying].

View File

@ -5809,10 +5809,8 @@ rb_str_aref(VALUE str, VALUE indx)
* self[regexp, capture = 0] -> new_string or nil
* self[substring] -> new_string or nil
*
* Returns the substring of +self+ specified by the arguments.
* See examples at {String Slices}[rdoc-ref:String@String+Slices].
* :include: doc/string/aref.rdoc
*
* Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
*/
static VALUE
@ -6026,30 +6024,14 @@ rb_str_aset(VALUE str, VALUE indx, VALUE val)
/*
* call-seq:
* self[index] = new_string
* self[start, length] = new_string
* self[range] = new_string
* self[regexp, capture = 0] = new_string
* self[substring] = new_string
* self[index] = other_string -> new_string
* self[start, length] = other_string -> new_string
* self[range] = other_string -> new_string
* self[regexp, capture = 0] = other_string -> new_string
* self[substring] = other_string -> new_string
*
* Replaces all, some, or none of the contents of +self+; returns +new_string+.
* See {String Slices}[rdoc-ref:String@String+Slices].
* :include: doc/string/aset.rdoc
*
* A few examples:
*
* s = 'foo'
* s[2] = 'rtune' # => "rtune"
* s # => "fortune"
* s[1, 5] = 'init' # => "init"
* s # => "finite"
* s[3..4] = 'al' # => "al"
* s # => "finale"
* s[/e$/] = 'ly' # => "ly"
* s # => "finally"
* s['lly'] = 'ncial' # => "ncial"
* s # => "financial"
*
* Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE
@ -6100,18 +6082,20 @@ rb_str_insert(VALUE str, VALUE idx, VALUE str2)
* slice!(regexp, capture = 0) -> new_string or nil
* slice!(substring) -> new_string or nil
*
* Removes and returns the substring of +self+ specified by the arguments.
* See {String Slices}[rdoc-ref:String@String+Slices].
* Like String#[] (and its alias String#slice), except that:
*
* - Performs substitutions in +self+ (not in a copy of +self+).
* - Returns the removed substring if any modifications were made, +nil+ otherwise.
*
* A few examples:
*
* string = "This is a string"
* string.slice!(2) #=> "i"
* string.slice!(3..6) #=> " is "
* string.slice!(/s.*t/) #=> "sa st"
* string.slice!("r") #=> "r"
* string #=> "Thing"
* s = 'hello'
* s.slice!('e') # => "e"
* s # => "hllo"
* s.slice!('e') # => nil
* s # => "hllo"
*
* Related: see {Modifying}[rdoc-ref:String@Modifying].
*/
static VALUE