diff --git a/doc/strscan/helper_methods.md b/doc/strscan/helper_methods.md deleted file mode 100644 index 6555a2ce66..0000000000 --- a/doc/strscan/helper_methods.md +++ /dev/null @@ -1,128 +0,0 @@ -## Helper Methods - -These helper methods display values returned by scanner's methods. - -### `put_situation(scanner)` - -Display scanner's situation: - -- Byte position (`#pos`). -- Character position (`#charpos`) -- Target string (`#rest`) and size (`#rest_size`). - -``` -scanner = StringScanner.new('foobarbaz') -scanner.scan(/foo/) -put_situation(scanner) -# Situation: -# pos: 3 -# charpos: 3 -# rest: "barbaz" -# rest_size: 6 -``` - -### `put_match_values(scanner)` - -Display the scanner's match values: - -``` -scanner = StringScanner.new('Fri Dec 12 1975 14:39') -pattern = /(?\w+) (?\w+) (?\d+) / -scanner.match?(pattern) -put_match_values(scanner) -# Basic match values: -# matched?: true -# matched_size: 11 -# pre_match: "" -# matched : "Fri Dec 12 " -# post_match: "1975 14:39" -# Captured match values: -# size: 4 -# captures: ["Fri", "Dec", "12"] -# named_captures: {"wday"=>"Fri", "month"=>"Dec", "day"=>"12"} -# values_at: ["Fri Dec 12 ", "Fri", "Dec", "12", nil] -# []: -# [0]: "Fri Dec 12 " -# [1]: "Fri" -# [2]: "Dec" -# [3]: "12" -# [4]: nil -``` - -### `match_values_cleared?(scanner)` - -Returns whether the scanner's match values are all properly cleared: - -``` -scanner = StringScanner.new('foobarbaz') -match_values_cleared?(scanner) # => true -put_match_values(scanner) -# Basic match values: -# matched?: false -# matched_size: nil -# pre_match: nil -# matched : nil -# post_match: nil -# Captured match values: -# size: nil -# captures: nil -# named_captures: {} -# values_at: nil -# [0]: nil -scanner.scan(/foo/) -match_values_cleared?(scanner) # => false -``` - -## The Code - -``` -def put_situation(scanner) - puts '# Situation:' - puts "# pos: #{scanner.pos}" - puts "# charpos: #{scanner.charpos}" - puts "# rest: #{scanner.rest.inspect}" - puts "# rest_size: #{scanner.rest_size}" -end -``` - -``` -def put_match_values(scanner) - puts '# Basic match values:' - puts "# matched?: #{scanner.matched?}" - value = scanner.matched_size || 'nil' - puts "# matched_size: #{value}" - puts "# pre_match: #{scanner.pre_match.inspect}" - puts "# matched : #{scanner.matched.inspect}" - puts "# post_match: #{scanner.post_match.inspect}" - puts '# Captured match values:' - puts "# size: #{scanner.size}" - puts "# captures: #{scanner.captures}" - puts "# named_captures: #{scanner.named_captures}" - if scanner.size.nil? - puts "# values_at: #{scanner.values_at(0)}" - puts "# [0]: #{scanner[0]}" - else - puts "# values_at: #{scanner.values_at(*(0..scanner.size))}" - puts "# []:" - scanner.size.times do |i| - puts "# [#{i}]: #{scanner[i].inspect}" - end - end -end -``` - -``` -def match_values_cleared?(scanner) - scanner.matched? == false && - scanner.matched_size.nil? && - scanner.matched.nil? && - scanner.pre_match.nil? && - scanner.post_match.nil? && - scanner.size.nil? && - scanner[0].nil? && - scanner.captures.nil? && - scanner.values_at(0..1).nil? && - scanner.named_captures == {} -end -``` - diff --git a/doc/strscan/link_refs.txt b/doc/strscan/link_refs.txt deleted file mode 100644 index 19f6f7ce5c..0000000000 --- a/doc/strscan/link_refs.txt +++ /dev/null @@ -1,17 +0,0 @@ -[1]: rdoc-ref:StringScanner@Stored+String -[2]: rdoc-ref:StringScanner@Byte+Position+-28Position-29 -[3]: rdoc-ref:StringScanner@Target+Substring -[4]: rdoc-ref:StringScanner@Setting+the+Target+Substring -[5]: rdoc-ref:StringScanner@Traversing+the+Target+Substring -[6]: https://docs.ruby-lang.org/en/master/Regexp.html -[7]: rdoc-ref:StringScanner@Character+Position -[8]: https://docs.ruby-lang.org/en/master/String.html#method-i-5B-5D -[9]: rdoc-ref:StringScanner@Match+Values -[10]: rdoc-ref:StringScanner@Fixed-Anchor+Property -[11]: rdoc-ref:StringScanner@Positions -[13]: rdoc-ref:StringScanner@Captured+Match+Values -[14]: rdoc-ref:StringScanner@Querying+the+Target+Substring -[15]: rdoc-ref:StringScanner@Searching+the+Target+Substring -[16]: https://docs.ruby-lang.org/en/master/Regexp.html#class-Regexp-label-Groups+and+Captures -[17]: rdoc-ref:StringScanner@Matching -[18]: rdoc-ref:StringScanner@Basic+Match+Values diff --git a/doc/strscan/strscan.md b/doc/strscan/strscan.md deleted file mode 100644 index c2558e9cf1..0000000000 --- a/doc/strscan/strscan.md +++ /dev/null @@ -1,543 +0,0 @@ -\Class `StringScanner` supports processing a stored string as a stream; -this code creates a new `StringScanner` object with string `'foobarbaz'`: - -``` -require 'strscan' -scanner = StringScanner.new('foobarbaz') -``` - -## About the Examples - -All examples here assume that `StringScanner` has been required: - -``` -require 'strscan' -``` - -Some examples here assume that these constants are defined: - -``` -MULTILINE_TEXT = <<~EOT -Go placidly amid the noise and haste, -and remember what peace there may be in silence. -EOT - -HIRAGANA_TEXT = 'こんにちは' - -ENGLISH_TEXT = 'Hello' -``` - -Some examples here assume that certain helper methods are defined: - -- `put_situation(scanner)`: - Displays the values of the scanner's - methods #pos, #charpos, #rest, and #rest_size. -- `put_match_values(scanner)`: - Displays the scanner's [match values][9]. -- `match_values_cleared?(scanner)`: - Returns whether the scanner's [match values][9] are cleared. - -See examples [here][ext/strscan/helper_methods_md.html]. - -## The `StringScanner` \Object - -This code creates a `StringScanner` object -(we'll call it simply a _scanner_), -and shows some of its basic properties: - -``` -scanner = StringScanner.new('foobarbaz') -scanner.string # => "foobarbaz" -put_situation(scanner) -# Situation: -# pos: 0 -# charpos: 0 -# rest: "foobarbaz" -# rest_size: 9 -``` - -The scanner has: - -* A stored string, which is: - - * Initially set by StringScanner.new(string) to the given `string` - (`'foobarbaz'` in the example above). - * Modifiable by methods #string=(new_string) and #concat(more_string). - * Returned by method #string. - - More at [Stored String][1] below. - -* A _position_; - a zero-based index into the bytes of the stored string (_not_ into its characters): - - * Initially set by StringScanner.new to `0`. - * Returned by method #pos. - * Modifiable explicitly by methods #reset, #terminate, and #pos=(new_pos). - * Modifiable implicitly (various traversing methods, among others). - - More at [Byte Position][2] below. - -* A target substring, - which is a trailing substring of the stored string; - it extends from the current position to the end of the stored string: - - * Initially set by StringScanner.new(string) to the given `string` - (`'foobarbaz'` in the example above). - * Returned by method #rest. - * Modified by any modification to either the stored string or the position. - - Most importantly: - the searching and traversing methods operate on the target substring, - which may be (and often is) less than the entire stored string. - - More at [Target Substring][3] below. - -## Stored \String - -The stored string is the string stored in the `StringScanner` object. - -Each of these methods sets, modifies, or returns the stored string: - -| Method | Effect | -|----------------------|-------------------------------------------------| -| ::new(string) | Creates a new scanner for the given string. | -| #string=(new_string) | Replaces the existing stored string. | -| #concat(more_string) | Appends a string to the existing stored string. | -| #string | Returns the stored string. | - -## Positions - -A `StringScanner` object maintains a zero-based byte position -and a zero-based character position. - -Each of these methods explicitly sets positions: - -| Method | Effect | -|--------------------------|----------------------------------------------------------| -| #reset | Sets both positions to zero (begining of stored string). | -| #terminate | Sets both positions to the end of the stored string. | -| #pos=(new_byte_position) | Sets byte position; adjusts character position. | - -### Byte Position (Position) - -The byte position (or simply _position_) -is a zero-based index into the bytes in the scanner's stored string; -for a new `StringScanner` object, the byte position is zero. - -When the byte position is: - -* Zero (at the beginning), the target substring is the entire stored string. -* Equal to the size of the stored string (at the end), - the target substring is the empty string `''`. - -To get or set the byte position: - -* \#pos: returns the byte position. -* \#pos=(new_pos): sets the byte position. - -Many methods use the byte position as the basis for finding matches; -many others set, increment, or decrement the byte position: - -``` -scanner = StringScanner.new('foobar') -scanner.pos # => 0 -scanner.scan(/foo/) # => "foo" # Match found. -scanner.pos # => 3 # Byte position incremented. -scanner.scan(/foo/) # => nil # Match not found. -scanner.pos # => 3 # Byte position not changed. -``` - -Some methods implicitly modify the byte position; -see: - -* [Setting the Target Substring][4]. -* [Traversing the Target Substring][5]. - -The values of these methods are derived directly from the values of #pos and #string: - -- \#charpos: the [character position][7]. -- \#rest: the [target substring][3]. -- \#rest_size: `rest.size`. - -### Character Position - -The character position is a zero-based index into the _characters_ -in the stored string; -for a new `StringScanner` object, the character position is zero. - -\Method #charpos returns the character position; -its value may not be reset explicitly. - -Some methods change (increment or reset) the character position; -see: - -* [Setting the Target Substring][4]. -* [Traversing the Target Substring][5]. - -Example (string includes multi-byte characters): - -``` -scanner = StringScanner.new(ENGLISH_TEXT) # Five 1-byte characters. -scanner.concat(HIRAGANA_TEXT) # Five 3-byte characters -scanner.string # => "Helloこんにちは" # Twenty bytes in all. -put_situation(scanner) -# Situation: -# pos: 0 -# charpos: 0 -# rest: "Helloこんにちは" -# rest_size: 20 -scanner.scan(/Hello/) # => "Hello" # Five 1-byte characters. -put_situation(scanner) -# Situation: -# pos: 5 -# charpos: 5 -# rest: "こんにちは" -# rest_size: 15 -scanner.getch # => "こ" # One 3-byte character. -put_situation(scanner) -# Situation: -# pos: 8 -# charpos: 6 -# rest: "んにちは" -# rest_size: 12``` - -## Target Substring - -The target substring is the the part of the [stored string][1] -that extends from the current [byte position][2] to the end of the stored string; -it is always either: - -- The entire stored string (byte position is zero). -- A trailing substring of the stored string (byte position positive). - -The target substring is returned by method #rest, -and its size is returned by method #rest_size. - -Examples: - -``` -scanner = StringScanner.new('foobarbaz') -put_situation(scanner) -# Situation: -# pos: 0 -# charpos: 0 -# rest: "foobarbaz" -# rest_size: 9 -scanner.pos = 3 -put_situation(scanner) -# Situation: -# pos: 3 -# charpos: 3 -# rest: "barbaz" -# rest_size: 6 -scanner.pos = 9 -put_situation(scanner) -# Situation: -# pos: 9 -# charpos: 9 -# rest: "" -# rest_size: 0 -``` - -### Setting the Target Substring - -The target substring is set whenever: - -* The [stored string][1] is set (position reset to zero; target substring set to stored string). -* The [byte position][2] is set (target substring adjusted accordingly). - -### Querying the Target Substring - -This table summarizes (details and examples at the links): - -| Method | Returns | -|------------|-----------------------------------| -| #rest | Target substring. | -| #rest_size | Size (bytes) of target substring. | - -### Searching the Target Substring - -A _search_ method examines the target substring, -but does not advance the [positions][11] -or (by implication) shorten the target substring. - -This table summarizes (details and examples at the links): - -| Method | Returns | Sets Match Values? | -|-----------------------|-----------------------------------------------|--------------------| -| #check(pattern) | Matched leading substring or +nil+. | Yes. | -| #check_until(pattern) | Matched substring (anywhere) or +nil+. | Yes. | -| #exist?(pattern) | Matched substring (anywhere) end index. | Yes. | -| #match?(pattern) | Size of matched leading substring or +nil+. | Yes. | -| #peek(size) | Leading substring of given length (bytes). | No. | -| #peek_byte | Integer leading byte or +nil+. | No. | -| #rest | Target substring (from byte position to end). | No. | - -### Traversing the Target Substring - -A _traversal_ method examines the target substring, -and, if successful: - -- Advances the [positions][11]. -- Shortens the target substring. - - -This table summarizes (details and examples at links): - -| Method | Returns | Sets Match Values? | -|----------------------|------------------------------------------------------|--------------------| -| #get_byte | Leading byte or +nil+. | No. | -| #getch | Leading character or +nil+. | No. | -| #scan(pattern) | Matched leading substring or +nil+. | Yes. | -| #scan_byte | Integer leading byte or +nil+. | No. | -| #scan_until(pattern) | Matched substring (anywhere) or +nil+. | Yes. | -| #skip(pattern) | Matched leading substring size or +nil+. | Yes. | -| #skip_until(pattern) | Position delta to end-of-matched-substring or +nil+. | Yes. | -| #unscan | +self+. | No. | - -## Querying the Scanner - -Each of these methods queries the scanner object -without modifying it (details and examples at links) - -| Method | Returns | -|---------------------|----------------------------------| -| #beginning_of_line? | +true+ or +false+. | -| #charpos | Character position. | -| #eos? | +true+ or +false+. | -| #fixed_anchor? | +true+ or +false+. | -| #inspect | String representation of +self+. | -| #pos | Byte position. | -| #rest | Target substring. | -| #rest_size | Size of target substring. | -| #string | Stored string. | - -## Matching - -`StringScanner` implements pattern matching via Ruby class [Regexp][6], -and its matching behaviors are the same as Ruby's -except for the [fixed-anchor property][10]. - -### Matcher Methods - -Each matcher method takes a single argument `pattern`, -and attempts to find a matching substring in the [target substring][3]. - -| Method | Pattern Type | Matches Target Substring | Success Return | May Update Positions? | -|--------------|-------------------|--------------------------|--------------------|-----------------------| -| #check | Regexp or String. | At beginning. | Matched substring. | No. | -| #check_until | Regexp. | Anywhere. | Substring. | No. | -| #match? | Regexp or String. | At beginning. | Updated position. | No. | -| #exist? | Regexp. | Anywhere. | Updated position. | No. | -| #scan | Regexp or String. | At beginning. | Matched substring. | Yes. | -| #scan_until | Regexp. | Anywhere. | Substring. | Yes. | -| #skip | Regexp or String. | At beginning. | Match size. | Yes. | -| #skip_until | Regexp. | Anywhere. | Position delta. | Yes. | - -
- -Which matcher you choose will depend on: - -- Where you want to find a match: - - - Only at the beginning of the target substring: - #check, #match?, #scan, #skip. - - Anywhere in the target substring: - #check_until, #exist?, #scan_until, #skip_until. - -- Whether you want to: - - - Traverse, by advancing the positions: - #scan, #scan_until, #skip, #skip_until. - - Keep the positions unchanged: - #check, #check_until, #exist?, #match?. - -- What you want for the return value: - - - The matched substring: #check, #check_until, #scan, #scan_until. - - The updated position: #exist?, #match?. - - The position delta: #skip_until. - - The match size: #skip. - -### Match Values - -The match values in a `StringScanner` object -generally contain the results of the most recent attempted match. - -Each match value may be thought of as: - -* _Clear_: Initially, or after an unsuccessful match attempt: - usually, `false`, `nil`, or `{}`. -* _Set_: After a successful match attempt: - `true`, string, array, or hash. - -Each of these methods clears match values: - -- ::new(string). -- \#reset. -- \#terminate. - -Each of these methods attempts a match based on a pattern, -and either sets match values (if successful) or clears them (if not); - -- \#check(pattern) -- \#check_until(pattern) -- \#exist?(pattern) -- \#match?(pattern) -- \#scan(pattern) -- \#scan_until(pattern) -- \#skip(pattern) -- \#skip_until(pattern) - -#### Basic Match Values - -Basic match values are those not related to captures. - -Each of these methods returns a basic match value: - -| Method | Return After Match | Return After No Match | -|-----------------|----------------------------------------|-----------------------| -| #matched? | +true+. | +false+. | -| #matched_size | Size of matched substring. | +nil+. | -| #matched | Matched substring. | +nil+. | -| #pre_match | Substring preceding matched substring. | +nil+. | -| #post_match | Substring following matched substring. | +nil+. | - -
- -See examples below. - -#### Captured Match Values - -Captured match values are those related to [captures][16]. - -Each of these methods returns a captured match value: - -| Method | Return After Match | Return After No Match | -|-----------------|-----------------------------------------|-----------------------| -| #size | Count of captured substrings. | +nil+. | -| #[](n) | nth captured substring. | +nil+. | -| #captures | Array of all captured substrings. | +nil+. | -| #values_at(*n) | Array of specified captured substrings. | +nil+. | -| #named_captures | Hash of named captures. | {}. | - -
- -See examples below. - -#### Match Values Examples - -Successful basic match attempt (no captures): - -``` -scanner = StringScanner.new('foobarbaz') -scanner.exist?(/bar/) -put_match_values(scanner) -# Basic match values: -# matched?: true -# matched_size: 3 -# pre_match: "foo" -# matched : "bar" -# post_match: "baz" -# Captured match values: -# size: 1 -# captures: [] -# named_captures: {} -# values_at: ["bar", nil] -# []: -# [0]: "bar" -# [1]: nil -``` - -Failed basic match attempt (no captures); - -``` -scanner = StringScanner.new('foobarbaz') -scanner.exist?(/nope/) -match_values_cleared?(scanner) # => true -``` - -Successful unnamed capture match attempt: - -``` -scanner = StringScanner.new('foobarbazbatbam') -scanner.exist?(/(foo)bar(baz)bat(bam)/) -put_match_values(scanner) -# Basic match values: -# matched?: true -# matched_size: 15 -# pre_match: "" -# matched : "foobarbazbatbam" -# post_match: "" -# Captured match values: -# size: 4 -# captures: ["foo", "baz", "bam"] -# named_captures: {} -# values_at: ["foobarbazbatbam", "foo", "baz", "bam", nil] -# []: -# [0]: "foobarbazbatbam" -# [1]: "foo" -# [2]: "baz" -# [3]: "bam" -# [4]: nil -``` - -Successful named capture match attempt; -same as unnamed above, except for #named_captures: - -``` -scanner = StringScanner.new('foobarbazbatbam') -scanner.exist?(/(?foo)bar(?baz)bat(?bam)/) -scanner.named_captures # => {"x"=>"foo", "y"=>"baz", "z"=>"bam"} -``` - -Failed unnamed capture match attempt: - -``` -scanner = StringScanner.new('somestring') -scanner.exist?(/(foo)bar(baz)bat(bam)/) -match_values_cleared?(scanner) # => true -``` - -Failed named capture match attempt; -same as unnamed above, except for #named_captures: - -``` -scanner = StringScanner.new('somestring') -scanner.exist?(/(?foo)bar(?baz)bat(?bam)/) -match_values_cleared?(scanner) # => false -scanner.named_captures # => {"x"=>nil, "y"=>nil, "z"=>nil} -``` - -## Fixed-Anchor Property - -Pattern matching in `StringScanner` is the same as in Ruby's, -except for its fixed-anchor property, -which determines the meaning of `'\A'`: - -* `false` (the default): matches the current byte position. - - ``` - scanner = StringScanner.new('foobar') - scanner.scan(/\A./) # => "f" - scanner.scan(/\A./) # => "o" - scanner.scan(/\A./) # => "o" - scanner.scan(/\A./) # => "b" - ``` - -* `true`: matches the beginning of the target substring; - never matches unless the byte position is zero: - - ``` - scanner = StringScanner.new('foobar', fixed_anchor: true) - scanner.scan(/\A./) # => "f" - scanner.scan(/\A./) # => nil - scanner.reset - scanner.scan(/\A./) # => "f" - ``` - -The fixed-anchor property is set when the `StringScanner` object is created, -and may not be modified -(see StringScanner.new); -method #fixed_anchor? returns the setting. - diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c index 6073651841..70a3ce5260 100644 --- a/ext/strscan/strscan.c +++ b/ext/strscan/strscan.c @@ -218,28 +218,16 @@ strscan_s_allocate(VALUE klass) } /* - * :markup: markdown - * :include: link_refs.txt - * * call-seq: - * StringScanner.new(string, fixed_anchor: false) -> string_scanner + * StringScanner.new(string, fixed_anchor: false) + * StringScanner.new(string, dup = false) * - * Returns a new `StringScanner` object whose [stored string][1] - * is the given `string`; - * sets the [fixed-anchor property][10]: + * Creates a new StringScanner object to scan over the given +string+. * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.string # => "foobarbaz" - * scanner.fixed_anchor? # => false - * put_situation(scanner) - * # Situation: - * # pos: 0 - * # charpos: 0 - * # rest: "foobarbaz" - * # rest_size: 9 - * ``` + * If +fixed_anchor+ is +true+, +\A+ always matches the beginning of + * the string. Otherwise, +\A+ always matches the current position. * + * +dup+ argument is obsolete and not used now. */ static VALUE strscan_initialize(int argc, VALUE *argv, VALUE self) @@ -278,14 +266,11 @@ check_strscan(VALUE obj) } /* - * :markup: markdown - * :include: link_refs.txt - * * call-seq: - * dup -> shallow_copy + * dup + * clone * - * Returns a shallow copy of `self`; - * the [stored string][1] in the copy is the same string as in `self`. + * Duplicates a StringScanner object. */ static VALUE strscan_init_copy(VALUE vself, VALUE vorig) @@ -312,13 +297,10 @@ strscan_init_copy(VALUE vself, VALUE vorig) ======================================================================= */ /* - * call-seq: - * StringScanner.must_C_version -> self + * call-seq: StringScanner.must_C_version * - * Returns +self+; defined for backward compatibility. + * This method is defined for backward compatibility. */ - - /* :nodoc: */ static VALUE strscan_s_mustc(VALUE self) { @@ -326,30 +308,7 @@ strscan_s_mustc(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * reset -> self - * - * Sets both [byte position][2] and [character position][7] to zero, - * and clears [match values][9]; - * returns +self+: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.exist?(/bar/) # => 6 - * scanner.reset # => # - * put_situation(scanner) - * # Situation: - * # pos: 0 - * # charpos: 0 - * # rest: "foobarbaz" - * # rest_size: 9 - * # => nil - * match_values_cleared?(scanner) # => true - * ``` - * + * Reset the scan pointer (index 0) and clear matching data. */ static VALUE strscan_reset(VALUE self) @@ -363,40 +322,11 @@ strscan_reset(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * * call-seq: - * terminate -> self - * - * Sets the scanner to end-of-string; - * returns +self+: - * - * - Sets both [positions][11] to end-of-stream. - * - Clears [match values][9]. - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.scan_until(/に/) - * put_situation(scanner) - * # Situation: - * # pos: 9 - * # charpos: 3 - * # rest: "ちは" - * # rest_size: 6 - * match_values_cleared?(scanner) # => false - * - * scanner.terminate # => # - * put_situation(scanner) - * # Situation: - * # pos: 15 - * # charpos: 5 - * # rest: "" - * # rest_size: 0 - * match_values_cleared?(scanner) # => true - * ``` + * terminate + * clear * + * Sets the scan pointer to the end of the string and clear matching data. */ static VALUE strscan_terminate(VALUE self) @@ -410,13 +340,9 @@ strscan_terminate(VALUE self) } /* - * call-seq: - * clear -> self - * - * This method is obsolete; use the equivalent method StringScanner#terminate. + * Equivalent to #terminate. + * This method is obsolete; use #terminate instead. */ - - /* :nodoc: */ static VALUE strscan_clear(VALUE self) { @@ -425,21 +351,7 @@ strscan_clear(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * string -> stored_string - * - * Returns the [stored string][1]: - * - * ``` - * scanner = StringScanner.new('foobar') - * scanner.string # => "foobar" - * scanner.concat('baz') - * scanner.string # => "foobarbaz" - * ``` - * + * Returns the string being scanned. */ static VALUE strscan_get_string(VALUE self) @@ -451,39 +363,10 @@ strscan_get_string(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * string = other_string -> other_string - * - * Replaces the [stored string][1] with the given `other_string`: - * - * - Sets both [positions][11] to zero. - * - Clears [match values][9]. - * - Returns `other_string`. - * - * ``` - * scanner = StringScanner.new('foobar') - * scanner.scan(/foo/) - * put_situation(scanner) - * # Situation: - * # pos: 3 - * # charpos: 3 - * # rest: "bar" - * # rest_size: 3 - * match_values_cleared?(scanner) # => false - * - * scanner.string = 'baz' # => "baz" - * put_situation(scanner) - * # Situation: - * # pos: 0 - * # charpos: 0 - * # rest: "baz" - * # rest_size: 3 - * match_values_cleared?(scanner) # => true - * ``` + * call-seq: string=(str) * + * Changes the string being scanned to +str+ and resets the scanner. + * Returns +str+. */ static VALUE strscan_set_string(VALUE self, VALUE str) @@ -498,33 +381,18 @@ strscan_set_string(VALUE self, VALUE str) } /* - * :markup: markdown - * :include: link_refs.txt - * * call-seq: - * concat(more_string) -> self + * concat(str) + * <<(str) * - * - Appends the given `more_string` - * to the [stored string][1]. - * - Returns `self`. - * - Does not affect the [positions][11] - * or [match values][9]. - * - * - * ``` - * scanner = StringScanner.new('foo') - * scanner.string # => "foo" - * scanner.terminate - * scanner.concat('barbaz') # => # - * scanner.string # => "foobarbaz" - * put_situation(scanner) - * # Situation: - * # pos: 3 - * # charpos: 3 - * # rest: "barbaz" - * # rest_size: 6 - * ``` + * Appends +str+ to the string being scanned. + * This method does not affect scan pointer. * + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.scan(/Fri /) + * s << " +1000 GMT" + * s.string # -> "Fri Dec 12 1975 14:39 +1000 GMT" + * s.scan(/Dec/) # -> "Dec" */ static VALUE strscan_concat(VALUE self, VALUE str) @@ -538,24 +406,18 @@ strscan_concat(VALUE self, VALUE str) } /* - * :markup: markdown - * :include: link_refs.txt + * Returns the byte position of the scan pointer. In the 'reset' position, this + * value is zero. In the 'terminated' position (i.e. the string is exhausted), + * this value is the bytesize of the string. * - * call-seq: - * pos -> byte_position - * - * Returns the integer [byte position][2], - * which may be different from the [character position][7]: - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.pos # => 0 - * scanner.getch # => "こ" # 3-byte character. - * scanner.charpos # => 1 - * scanner.pos # => 3 - * ``` + * In short, it's a 0-based index into bytes of the string. * + * s = StringScanner.new('test string') + * s.pos # -> 0 + * s.scan_until /str/ # -> "test str" + * s.pos # -> 8 + * s.terminate # -> # + * s.pos # -> 11 */ static VALUE strscan_get_pos(VALUE self) @@ -567,29 +429,17 @@ strscan_get_pos(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt + * Returns the character position of the scan pointer. In the 'reset' position, this + * value is zero. In the 'terminated' position (i.e. the string is exhausted), + * this value is the size of the string. * - * call-seq: - * charpos -> character_position - * - * Returns the [character position][7] (initially zero), - * which may be different from the [byte position][2] - * given by method #pos: - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.getch # => "こ" # 3-byte character. - * scanner.getch # => "ん" # 3-byte character. - * put_situation(scanner) - * # Situation: - * # pos: 6 - * # charpos: 2 - * # rest: "にちは" - * # rest_size: 9 - * ``` + * In short, it's a 0-based index into the string. * + * s = StringScanner.new("abc\u00e4def\u00f6ghi") + * s.charpos # -> 0 + * s.scan_until(/\u00e4/) # -> "abc\u00E4" + * s.pos # -> 5 + * s.charpos # -> 4 */ static VALUE strscan_get_charpos(VALUE self) @@ -602,36 +452,13 @@ strscan_get_charpos(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: pos=(n) * - * call-seq: - * pos = n -> n - * - * Sets the [byte position][2] and the [character position][11]; - * returns `n`. - * - * Does not affect [match values][9]. - * - * For non-negative `n`, sets the position to `n`: - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.pos = 3 # => 3 - * scanner.rest # => "んにちは" - * scanner.charpos # => 1 - * ``` - * - * For negative `n`, counts from the end of the [stored string][1]: - * - * ``` - * scanner.pos = -9 # => -9 - * scanner.pos # => 6 - * scanner.rest # => "にちは" - * scanner.charpos # => 2 - * ``` + * Sets the byte position of the scan pointer. * + * s = StringScanner.new('test string') + * s.pos = 7 # -> 7 + * s.rest # -> "ring" */ static VALUE strscan_set_pos(VALUE self, VALUE v) @@ -835,60 +662,19 @@ strscan_do_scan(VALUE self, VALUE pattern, int succptr, int getstr, int headonly } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: scan(pattern) => String * - * call-seq: - * scan(pattern) -> substring or nil + * Tries to match with +pattern+ at the current position. If there's a match, + * the scanner advances the "scan pointer" and returns the matched string. + * Otherwise, the scanner returns +nil+. * - * Attempts to [match][17] the given `pattern` - * at the beginning of the [target substring][3]. - * - * If the match succeeds: - * - * - Returns the matched substring. - * - Increments the [byte position][2] by substring.bytesize, - * and may increment the [character position][7]. - * - Sets [match values][9]. - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.pos = 6 - * scanner.scan(/に/) # => "に" - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "こん" - * # matched : "に" - * # post_match: "ちは" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["に", nil] - * # []: - * # [0]: "に" - * # [1]: nil - * put_situation(scanner) - * # Situation: - * # pos: 9 - * # charpos: 3 - * # rest: "ちは" - * # rest_size: 6 - * ``` - * - * If the match fails: - * - * - Returns `nil`. - * - Does not increment byte and character positions. - * - Clears match values. - * - * ``` - * scanner.scan(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * s = StringScanner.new('test string') + * p s.scan(/\w+/) # -> "test" + * p s.scan(/\w+/) # -> nil + * p s.scan(/\s+/) # -> " " + * p s.scan("str") # -> "str" + * p s.scan(/\w+/) # -> "ing" + * p s.scan(/./) # -> nil * */ static VALUE @@ -898,60 +684,16 @@ strscan_scan(VALUE self, VALUE re) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: match?(pattern) * - * call-seq: - * match?(pattern) -> updated_position or nil - * - * Attempts to [match][17] the given `pattern` - * at the beginning of the [target substring][3]; - * does not modify the [positions][11]. - * - * If the match succeeds: - * - * - Sets [match values][9]. - * - Returns the size in bytes of the matched substring. - * - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.pos = 3 - * scanner.match?(/bar/) => 3 - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "foo" - * # matched : "bar" - * # post_match: "baz" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["bar", nil] - * # []: - * # [0]: "bar" - * # [1]: nil - * put_situation(scanner) - * # Situation: - * # pos: 3 - * # charpos: 3 - * # rest: "barbaz" - * # rest_size: 6 - * ``` - * - * If the match fails: - * - * - Clears match values. - * - Returns `nil`. - * - Does not increment positions. - * - * ``` - * scanner.match?(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * Tests whether the given +pattern+ is matched from the current scan pointer. + * Returns the length of the match, or +nil+. The scan pointer is not advanced. * + * s = StringScanner.new('test string') + * p s.match?(/\w+/) # -> 4 + * p s.match?(/\w+/) # -> 4 + * p s.match?("test") # -> 4 + * p s.match?(/\s+/) # -> nil */ static VALUE strscan_match_p(VALUE self, VALUE re) @@ -960,52 +702,21 @@ strscan_match_p(VALUE self, VALUE re) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: skip(pattern) * - * call-seq: - * skip(pattern) match_size or nil + * Attempts to skip over the given +pattern+ beginning with the scan pointer. + * If it matches, the scan pointer is advanced to the end of the match, and the + * length of the match is returned. Otherwise, +nil+ is returned. * - * Attempts to [match][17] the given `pattern` - * at the beginning of the [target substring][3]; + * It's similar to #scan, but without returning the matched string. * - * If the match succeeds: - * - * - Increments the [byte position][2] by substring.bytesize, - * and may increment the [character position][7]. - * - Sets [match values][9]. - * - Returns the size (bytes) of the matched substring. - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.pos = 6 - * scanner.skip(/に/) # => 3 - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "こん" - * # matched : "に" - * # post_match: "ちは" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["に", nil] - * # []: - * # [0]: "に" - * # [1]: nil - * put_situation(scanner) - * # Situation: - * # pos: 9 - * # charpos: 3 - * # rest: "ちは" - * # rest_size: 6 - * - * scanner.skip(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * s = StringScanner.new('test string') + * p s.skip(/\w+/) # -> 4 + * p s.skip(/\w+/) # -> nil + * p s.skip(/\s+/) # -> 1 + * p s.skip("st") # -> 2 + * p s.skip(/\w+/) # -> 4 + * p s.skip(/./) # -> nil * */ static VALUE @@ -1015,59 +726,19 @@ strscan_skip(VALUE self, VALUE re) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: check(pattern) * - * call-seq: - * check(pattern) -> matched_substring or nil + * This returns the value that #scan would return, without advancing the scan + * pointer. The match register is affected, though. * - * Attempts to [match][17] the given `pattern` - * at the beginning of the [target substring][3]; - * does not modify the [positions][11]. - * - * If the match succeeds: - * - * - Returns the matched substring. - * - Sets all [match values][9]. - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.pos = 3 - * scanner.check('bar') # => "bar" - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "foo" - * # matched : "bar" - * # post_match: "baz" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["bar", nil] - * # []: - * # [0]: "bar" - * # [1]: nil - * # => 0..1 - * put_situation(scanner) - * # Situation: - * # pos: 3 - * # charpos: 3 - * # rest: "barbaz" - * # rest_size: 6 - * ``` - * - * If the match fails: - * - * - Returns `nil`. - * - Clears all [match values][9]. - * - * ``` - * scanner.check(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.check /Fri/ # -> "Fri" + * s.pos # -> 0 + * s.matched # -> "Fri" + * s.check /12/ # -> nil + * s.matched # -> nil * + * Mnemonic: it "checks" to see whether a #scan will return a value. */ static VALUE strscan_check(VALUE self, VALUE re) @@ -1076,24 +747,15 @@ strscan_check(VALUE self, VALUE re) } /* - * call-seq: - * scan_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or nil + * call-seq: scan_full(pattern, advance_pointer_p, return_string_p) * - * Equivalent to one of the following: - * - * - +advance_pointer_p+ +true+: - * - * - +return_string_p+ +true+: StringScanner#scan(pattern). - * - +return_string_p+ +false+: StringScanner#skip(pattern). - * - * - +advance_pointer_p+ +false+: - * - * - +return_string_p+ +true+: StringScanner#check(pattern). - * - +return_string_p+ +false+: StringScanner#match?(pattern). + * Tests whether the given +pattern+ is matched from the current scan pointer. + * Advances the scan pointer if +advance_pointer_p+ is true. + * Returns the matched string if +return_string_p+ is true. + * The match register is affected. * + * "full" means "#scan with full parameters". */ - - /* :nodoc: */ static VALUE strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f) { @@ -1101,62 +763,16 @@ strscan_scan_full(VALUE self, VALUE re, VALUE s, VALUE f) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: scan_until(pattern) * - * call-seq: - * scan_until(pattern) -> substring or nil - * - * Attempts to [match][17] the given `pattern` - * anywhere (at any [position][2]) in the [target substring][3]. - * - * If the match attempt succeeds: - * - * - Sets [match values][9]. - * - Sets the [byte position][2] to the end of the matched substring; - * may adjust the [character position][7]. - * - Returns the matched substring. - * - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.pos = 6 - * scanner.scan_until(/ち/) # => "にち" - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "こんに" - * # matched : "ち" - * # post_match: "は" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["ち", nil] - * # []: - * # [0]: "ち" - * # [1]: nil - * put_situation(scanner) - * # Situation: - * # pos: 12 - * # charpos: 4 - * # rest: "は" - * # rest_size: 3 - * ``` - * - * If the match attempt fails: - * - * - Clears match data. - * - Returns `nil`. - * - Does not update positions. - * - * ``` - * scanner.scan_until(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * Scans the string _until_ the +pattern+ is matched. Returns the substring up + * to and including the end of the match, advancing the scan pointer to that + * location. If there is no match, +nil+ is returned. * + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.scan_until(/1/) # -> "Fri Dec 1" + * s.pre_match # -> "Fri Dec " + * s.scan_until(/XYZ/) # -> nil */ static VALUE strscan_scan_until(VALUE self, VALUE re) @@ -1165,61 +781,17 @@ strscan_scan_until(VALUE self, VALUE re) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: exist?(pattern) * - * call-seq: - * exist?(pattern) -> byte_offset or nil - * - * Attempts to [match][17] the given `pattern` - * anywhere (at any [position][2]) - * n the [target substring][3]; - * does not modify the [positions][11]. - * - * If the match succeeds: - * - * - Returns a byte offset: - * the distance in bytes between the current [position][2] - * and the end of the matched substring. - * - Sets all [match values][9]. - * - * ``` - * scanner = StringScanner.new('foobarbazbatbam') - * scanner.pos = 6 - * scanner.exist?(/bat/) # => 6 - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "foobarbaz" - * # matched : "bat" - * # post_match: "bam" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["bat", nil] - * # []: - * # [0]: "bat" - * # [1]: nil - * put_situation(scanner) - * # Situation: - * # pos: 6 - * # charpos: 6 - * # rest: "bazbatbam" - * # rest_size: 9 - * ``` - * - * If the match fails: - * - * - Returns `nil`. - * - Clears all [match values][9]. - * - * ``` - * scanner.exist?(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * Looks _ahead_ to see if the +pattern+ exists _anywhere_ in the string, + * without advancing the scan pointer. This predicates whether a #scan_until + * will return a value. * + * s = StringScanner.new('test string') + * s.exist? /s/ # -> 3 + * s.scan /test/ # -> "test" + * s.exist? /s/ # -> 2 + * s.exist? /e/ # -> nil */ static VALUE strscan_exist_p(VALUE self, VALUE re) @@ -1228,59 +800,20 @@ strscan_exist_p(VALUE self, VALUE re) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: skip_until(pattern) * - * call-seq: - * skip_until(pattern) -> matched_substring_size or nil + * Advances the scan pointer until +pattern+ is matched and consumed. Returns + * the number of bytes advanced, or +nil+ if no match was found. * - * Attempts to [match][17] the given `pattern` - * anywhere (at any [position][2]) in the [target substring][3]; - * does not modify the positions. + * Look ahead to match +pattern+, and advance the scan pointer to the _end_ + * of the match. Return the number of characters advanced, or +nil+ if the + * match was unsuccessful. * - * If the match attempt succeeds: - * - * - Sets [match values][9]. - * - Returns the size of the matched substring. - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * scanner.pos = 6 - * scanner.skip_until(/ち/) # => 6 - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "こんに" - * # matched : "ち" - * # post_match: "は" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["ち", nil] - * # []: - * # [0]: "ち" - * # [1]: nil - * put_situation(scanner) - * # Situation: - * # pos: 12 - * # charpos: 4 - * # rest: "は" - * # rest_size: 3 - * ``` - * - * If the match attempt fails: - * - * - Clears match values. - * - Returns `nil`. - * - * ``` - * scanner.skip_until(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * It's similar to #scan_until, but without returning the intervening string. * + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.skip_until /12/ # -> 10 + * s # */ static VALUE strscan_skip_until(VALUE self, VALUE re) @@ -1289,61 +822,17 @@ strscan_skip_until(VALUE self, VALUE re) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: check_until(pattern) * - * call-seq: - * check_until(pattern) -> substring or nil + * This returns the value that #scan_until would return, without advancing the + * scan pointer. The match register is affected, though. * - * Attempts to [match][17] the given `pattern` - * anywhere (at any [position][2]) - * in the [target substring][3]; - * does not modify the [positions][11]. - * - * If the match succeeds: - * - * - Sets all [match values][9]. - * - Returns the matched substring, - * which extends from the current [position][2] - * to the end of the matched substring. - * - * ``` - * scanner = StringScanner.new('foobarbazbatbam') - * scanner.pos = 6 - * scanner.check_until(/bat/) # => "bazbat" - * put_match_values(scanner) - * # Basic match values: - * # matched?: true - * # matched_size: 3 - * # pre_match: "foobarbaz" - * # matched : "bat" - * # post_match: "bam" - * # Captured match values: - * # size: 1 - * # captures: [] - * # named_captures: {} - * # values_at: ["bat", nil] - * # []: - * # [0]: "bat" - * # [1]: nil - * put_situation(scanner) - * # Situation: - * # pos: 6 - * # charpos: 6 - * # rest: "bazbatbam" - * # rest_size: 9 - * ``` - * - * If the match fails: - * - * - Clears all [match values][9]. - * - Returns `nil`. - * - * ``` - * scanner.check_until(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * ``` + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.check_until /12/ # -> "Fri Dec 12" + * s.pos # -> 0 + * s.matched # -> 12 * + * Mnemonic: it "checks" to see whether a #scan_until will return a value. */ static VALUE strscan_check_until(VALUE self, VALUE re) @@ -1352,24 +841,14 @@ strscan_check_until(VALUE self, VALUE re) } /* - * call-seq: - * search_full(pattern, advance_pointer_p, return_string_p) -> matched_substring or position_delta or nil - * - * Equivalent to one of the following: - * - * - +advance_pointer_p+ +true+: - * - * - +return_string_p+ +true+: StringScanner#scan_until(pattern). - * - +return_string_p+ +false+: StringScanner#skip_until(pattern). - * - * - +advance_pointer_p+ +false+: - * - * - +return_string_p+ +true+: StringScanner#check_until(pattern). - * - +return_string_p+ +false+: StringScanner#exist?(pattern). + * call-seq: search_full(pattern, advance_pointer_p, return_string_p) * + * Scans the string _until_ the +pattern+ is matched. + * Advances the scan pointer if +advance_pointer_p+, otherwise not. + * Returns the matched string if +return_string_p+ is true, otherwise + * returns the number of bytes advanced. + * This method does affect the match register. */ - - /* :nodoc: */ static VALUE strscan_search_full(VALUE self, VALUE re, VALUE s, VALUE f) { @@ -1389,53 +868,17 @@ adjust_registers_to_matched(struct strscanner *p) } /* - * :markup: markdown - * :include: link_refs.txt + * Scans one character and returns it. + * This method is multibyte character sensitive. * - * call-seq: - * getch -> character or nil - * - * Returns the next (possibly multibyte) character, - * if available: - * - * - If the [position][2] - * is at the beginning of a character: - * - * - Returns the character. - * - Increments the [character position][7] by 1. - * - Increments the [byte position][2] - * by the size (in bytes) of the character. - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * scanner.string # => "こんにちは" - * [scanner.getch, scanner.pos, scanner.charpos] # => ["こ", 3, 1] - * [scanner.getch, scanner.pos, scanner.charpos] # => ["ん", 6, 2] - * [scanner.getch, scanner.pos, scanner.charpos] # => ["に", 9, 3] - * [scanner.getch, scanner.pos, scanner.charpos] # => ["ち", 12, 4] - * [scanner.getch, scanner.pos, scanner.charpos] # => ["は", 15, 5] - * [scanner.getch, scanner.pos, scanner.charpos] # => [nil, 15, 5] - * ``` - * - * - If the [position][2] is within a multi-byte character - * (that is, not at its beginning), - * behaves like #get_byte (returns a 1-byte character): - * - * ``` - * scanner.pos = 1 - * [scanner.getch, scanner.pos, scanner.charpos] # => ["\x81", 2, 2] - * [scanner.getch, scanner.pos, scanner.charpos] # => ["\x93", 3, 1] - * [scanner.getch, scanner.pos, scanner.charpos] # => ["ん", 6, 2] - * ``` - * - * - If the [position][2] is at the end of the [stored string][1], - * returns `nil` and does not modify the positions: - * - * ``` - * scanner.terminate - * [scanner.getch, scanner.pos, scanner.charpos] # => [nil, 15, 5] - * ``` + * s = StringScanner.new("ab") + * s.getch # => "a" + * s.getch # => "b" + * s.getch # => nil * + * s = StringScanner.new("\244\242".force_encoding("euc-jp")) + * s.getch # => "\x{A4A2}" # Japanese hira-kana "A" in EUC-JP + * s.getch # => nil */ static VALUE strscan_getch(VALUE self) @@ -1460,13 +903,19 @@ strscan_getch(VALUE self) } /* - * call-seq: - * scan_byte -> integer_byte - * * Scans one byte and returns it as an integer. * This method is not multibyte character sensitive. * See also: #getch. * + * s = StringScanner.new('ab') + * s.scan_byte # => 97 + * s.scan_byte # => 98 + * s.scan_byte # => nil + * + * s = StringScanner.new("\244\242".force_encoding("euc-jp")) + * s.scan_byte # => 0xA4 + * s.scan_byte # => 0xA2 + * s.scan_byte # => nil */ static VALUE strscan_scan_byte(VALUE self) @@ -1505,40 +954,19 @@ strscan_peek_byte(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt + * Scans one byte and returns it. + * This method is not multibyte character sensitive. + * See also: #getch. * - * call-seq: - * get_byte -> byte_as_character or nil - * - * Returns the next byte, if available: - * - * - If the [position][2] - * is not at the end of the [stored string][1]: - * - * - Returns the next byte. - * - Increments the [byte position][2]. - * - Adjusts the [character position][7]. - * - * ``` - * scanner = StringScanner.new(HIRAGANA_TEXT) - * # => # - * scanner.string # => "こんにちは" - * [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\xE3", 1, 1] - * [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x81", 2, 2] - * [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x93", 3, 1] - * [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\xE3", 4, 2] - * [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x82", 5, 3] - * [scanner.get_byte, scanner.pos, scanner.charpos] # => ["\x93", 6, 2] - * ``` - - * - Otherwise, returns `nil`, and does not change the positions. - * - * ``` - * scanner.terminate - * [scanner.get_byte, scanner.pos, scanner.charpos] # => [nil, 15, 5] - * ``` + * s = StringScanner.new('ab') + * s.get_byte # => "a" + * s.get_byte # => "b" + * s.get_byte # => nil * + * s = StringScanner.new("\244\242".force_encoding("euc-jp")) + * s.get_byte # => "\xA4" + * s.get_byte # => "\xA2" + * s.get_byte # => nil */ static VALUE strscan_get_byte(VALUE self) @@ -1560,14 +988,9 @@ strscan_get_byte(VALUE self) } /* - * call-seq: - * getbyte - * * Equivalent to #get_byte. * This method is obsolete; use #get_byte instead. */ - - /* :nodoc: */ static VALUE strscan_getbyte(VALUE self) { @@ -1576,22 +999,14 @@ strscan_getbyte(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: peek(len) * - * call-seq: - * peek(length) -> substring + * Extracts a string corresponding to string[pos,len], without + * advancing the scan pointer. * - * Returns the substring `string[pos, length]`; - * does not update [match values][9] or [positions][11]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.pos = 3 - * scanner.peek(3) # => "bar" - * scanner.terminate - * scanner.peek(3) # => "" - * ``` + * s = StringScanner.new('test string') + * s.peek(7) # => "test st" + * s.peek(7) # => "test st" * */ static VALUE @@ -1611,14 +1026,9 @@ strscan_peek(VALUE self, VALUE vlen) } /* - * call-seq: - * peep - * * Equivalent to #peek. * This method is obsolete; use #peek instead. */ - - /* :nodoc: */ static VALUE strscan_peep(VALUE self, VALUE vlen) { @@ -1627,42 +1037,15 @@ strscan_peep(VALUE self, VALUE vlen) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * unscan -> self - * - * Sets the [position][2] to its value previous to the recent successful - * [match][17] attempt: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.scan(/foo/) - * put_situation(scanner) - * # Situation: - * # pos: 3 - * # charpos: 3 - * # rest: "barbaz" - * # rest_size: 6 - * scanner.unscan - * # => # - * put_situation(scanner) - * # Situation: - * # pos: 0 - * # charpos: 0 - * # rest: "foobarbaz" - * # rest_size: 9 - * ``` - * - * Raises an exception if match values are clear: - * - * ``` - * scanner.scan(/nope/) # => nil - * match_values_cleared?(scanner) # => true - * scanner.unscan # Raises StringScanner::Error. - * ``` + * Sets the scan pointer to the previous position. Only one previous position is + * remembered, and it changes with each scanning operation. * + * s = StringScanner.new('test string') + * s.scan(/\w+/) # => "test" + * s.unscan + * s.scan(/../) # => "te" + * s.scan(/\d/) # => nil + * s.unscan # ScanError: unscan failed: previous match record not exist */ static VALUE strscan_unscan(VALUE self) @@ -1678,37 +1061,16 @@ strscan_unscan(VALUE self) } /* + * Returns +true+ if and only if the scan pointer is at the beginning of the line. * - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * beginning_of_line? -> true or false - * - * Returns whether the [position][2] is at the beginning of a line; - * that is, at the beginning of the [stored string][1] - * or immediately after a newline: - * - * scanner = StringScanner.new(MULTILINE_TEXT) - * scanner.string - * # => "Go placidly amid the noise and haste,\nand remember what peace there may be in silence.\n" - * scanner.pos # => 0 - * scanner.beginning_of_line? # => true - * - * scanner.scan_until(/,/) # => "Go placidly amid the noise and haste," - * scanner.beginning_of_line? # => false - * - * scanner.scan(/\n/) # => "\n" - * scanner.beginning_of_line? # => true - * - * scanner.terminate - * scanner.beginning_of_line? # => true - * - * scanner.concat('x') - * scanner.terminate - * scanner.beginning_of_line? # => false - * - * StringScanner#bol? is an alias for StringScanner#beginning_of_line?. + * s = StringScanner.new("test\ntest\n") + * s.bol? # => true + * s.scan(/te/) + * s.bol? # => false + * s.scan(/st\n/) + * s.bol? # => true + * s.terminate + * s.bol? # => true */ static VALUE strscan_bol_p(VALUE self) @@ -1722,24 +1084,14 @@ strscan_bol_p(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * eos? -> true or false - * - * Returns whether the [position][2] - * is at the end of the [stored string][1]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.eos? # => false - * pos = 3 - * scanner.eos? # => false - * scanner.terminate - * scanner.eos? # => true - * ``` + * Returns +true+ if the scan pointer is at the end of the string. * + * s = StringScanner.new('test string') + * p s.eos? # => false + * s.scan(/test/) + * p s.eos? # => false + * s.terminate + * p s.eos? # => true */ static VALUE strscan_eos_p(VALUE self) @@ -1751,14 +1103,9 @@ strscan_eos_p(VALUE self) } /* - * call-seq: - * empty? - * * Equivalent to #eos?. * This method is obsolete, use #eos? instead. */ - - /* :nodoc: */ static VALUE strscan_empty_p(VALUE self) { @@ -1767,9 +1114,6 @@ strscan_empty_p(VALUE self) } /* - * call-seq: - * rest? - * * Returns true if and only if there is more data in the string. See #eos?. * This method is obsolete; use #eos? instead. * @@ -1778,8 +1122,6 @@ strscan_empty_p(VALUE self) * s.eos? # => false * s.rest? # => true */ - - /* :nodoc: */ static VALUE strscan_rest_p(VALUE self) { @@ -1790,26 +1132,13 @@ strscan_rest_p(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * matched? -> true or false - * - * Returns `true` of the most recent [match attempt][17] was successful, - * `false` otherwise; - * see [Basic Matched Values][18]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.matched? # => false - * scanner.pos = 3 - * scanner.exist?(/baz/) # => 6 - * scanner.matched? # => true - * scanner.exist?(/nope/) # => nil - * scanner.matched? # => false - * ``` + * Returns +true+ if and only if the last match was successful. * + * s = StringScanner.new('test string') + * s.match?(/\w+/) # => 4 + * s.matched? # => true + * s.match?(/\d+/) # => nil + * s.matched? # => false */ static VALUE strscan_matched_p(VALUE self) @@ -1821,27 +1150,11 @@ strscan_matched_p(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * matched -> matched_substring or nil - * - * Returns the matched substring from the most recent [match][17] attempt - * if it was successful, - * or `nil` otherwise; - * see [Basic Matched Values][18]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.matched # => nil - * scanner.pos = 3 - * scanner.match?(/bar/) # => 3 - * scanner.matched # => "bar" - * scanner.match?(/nope/) # => nil - * scanner.matched # => nil - * ``` + * Returns the last matched string. * + * s = StringScanner.new('test string') + * s.match?(/\w+/) # -> 4 + * s.matched # -> "test" */ static VALUE strscan_matched(VALUE self) @@ -1856,29 +1169,15 @@ strscan_matched(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * matched_size -> substring_size or nil - * - * Returns the size (in bytes) of the matched substring - * from the most recent match [match attempt][17] if it was successful, - * or `nil` otherwise; - * see [Basic Matched Values][18]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.matched_size # => nil - * - * pos = 3 - * scanner.exist?(/baz/) # => 9 - * scanner.matched_size # => 3 - * - * scanner.exist?(/nope/) # => nil - * scanner.matched_size # => nil - * ``` + * Returns the size of the most recent match in bytes, or +nil+ if there + * was no recent match. This is different than matched.size, + * which will return the size in characters. * + * s = StringScanner.new('test string') + * s.check /\w+/ # -> "test" + * s.matched_size # -> 4 + * s.check /\d+/ # -> nil + * s.matched_size # -> nil */ static VALUE strscan_matched_size(VALUE self) @@ -1909,75 +1208,30 @@ name_to_backref_number(struct re_registers *regs, VALUE regexp, const char* name } /* + * call-seq: [](n) * - * :markup: markdown - * :include: link_refs.txt + * Returns the n-th subgroup in the most recent match. * - * call-seq: - * [](specifier) -> substring or nil - * - * Returns a captured substring or `nil`; - * see [Captured Match Values][13]. - * - * When there are captures: - * - * ``` - * scanner = StringScanner.new('Fri Dec 12 1975 14:39') - * scanner.scan(/(?\w+) (?\w+) (?\d+) /) - * ``` - * - * - `specifier` zero: returns the entire matched substring: - * - * ``` - * scanner[0] # => "Fri Dec 12 " - * scanner.pre_match # => "" - * scanner.post_match # => "1975 14:39" - * ``` - * - * - `specifier` positive integer. returns the `n`th capture, or `nil` if out of range: - * - * ``` - * scanner[1] # => "Fri" - * scanner[2] # => "Dec" - * scanner[3] # => "12" - * scanner[4] # => nil - * ``` - * - * - `specifier` negative integer. counts backward from the last subgroup: - * - * ``` - * scanner[-1] # => "12" - * scanner[-4] # => "Fri Dec 12 " - * scanner[-5] # => nil - * ``` - * - * - `specifier` symbol or string. returns the named subgroup, or `nil` if no such: - * - * ``` - * scanner[:wday] # => "Fri" - * scanner['wday'] # => "Fri" - * scanner[:month] # => "Dec" - * scanner[:day] # => "12" - * scanner[:nope] # => nil - * ``` - * - * When there are no captures, only `[0]` returns non-`nil`: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.exist?(/bar/) - * scanner[0] # => "bar" - * scanner[1] # => nil - * ``` - * - * For a failed match, even `[0]` returns `nil`: - * - * ``` - * scanner.scan(/nope/) # => nil - * scanner[0] # => nil - * scanner[1] # => nil - * ``` + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 " + * s[0] # -> "Fri Dec 12 " + * s[1] # -> "Fri" + * s[2] # -> "Dec" + * s[3] # -> "12" + * s.post_match # -> "1975 14:39" + * s.pre_match # -> "" * + * s.reset + * s.scan(/(?\w+) (?\w+) (?\d+) /) # -> "Fri Dec 12 " + * s[0] # -> "Fri Dec 12 " + * s[1] # -> "Fri" + * s[2] # -> "Dec" + * s[3] # -> "12" + * s[:wday] # -> "Fri" + * s[:month] # -> "Dec" + * s[:day] # -> "12" + * s.post_match # -> "1975 14:39" + * s.pre_match # -> "" */ static VALUE strscan_aref(VALUE self, VALUE idx) @@ -2014,28 +1268,14 @@ strscan_aref(VALUE self, VALUE idx) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: size * - * call-seq: - * size -> captures_count - * - * Returns the count of captures if the most recent match attempt succeeded, `nil` otherwise; - * see [Captures Match Values][13]: - * - * ``` - * scanner = StringScanner.new('Fri Dec 12 1975 14:39') - * scanner.size # => nil - * - * pattern = /(?\w+) (?\w+) (?\d+) / - * scanner.match?(pattern) - * scanner.values_at(*0..scanner.size) # => ["Fri Dec 12 ", "Fri", "Dec", "12", nil] - * scanner.size # => 4 - * - * scanner.match?(/nope/) # => nil - * scanner.size # => nil - * ``` + * Returns the amount of subgroups in the most recent match. + * The full match counts as a subgroup. * + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 " + * s.size # -> 4 */ static VALUE strscan_size(VALUE self) @@ -2048,30 +1288,16 @@ strscan_size(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: captures * - * call-seq: - * captures -> substring_array or nil - * - * Returns the array of [captured match values][13] at indexes `(1..)` - * if the most recent match attempt succeeded, or `nil` otherwise: - * - * ``` - * scanner = StringScanner.new('Fri Dec 12 1975 14:39') - * scanner.captures # => nil - * - * scanner.exist?(/(?\w+) (?\w+) (?\d+) /) - * scanner.captures # => ["Fri", "Dec", "12"] - * scanner.values_at(*0..4) # => ["Fri Dec 12 ", "Fri", "Dec", "12", nil] - * - * scanner.exist?(/Fri/) - * scanner.captures # => [] - * - * scanner.scan(/nope/) - * scanner.captures # => nil - * ``` + * Returns the subgroups in the most recent match (not including the full match). + * If nothing was priorly matched, it returns nil. * + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.scan(/(\w+) (\w+) (\d+) (1980)?/) # -> "Fri Dec 12 " + * s.captures # -> ["Fri", "Dec", "12", nil] + * s.scan(/(\w+) (\w+) (\d+) (1980)?/) # -> nil + * s.captures # -> nil */ static VALUE strscan_captures(VALUE self) @@ -2101,25 +1327,17 @@ strscan_captures(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt + * call-seq: + * scanner.values_at( i1, i2, ... iN ) -> an_array * - * call-seq: - * values_at(*specifiers) -> array_of_captures or nil - * - * Returns an array of captured substrings, or `nil` of none. - * - * For each `specifier`, the returned substring is `[specifier]`; - * see #[]. - * - * ``` - * scanner = StringScanner.new('Fri Dec 12 1975 14:39') - * pattern = /(?\w+) (?\w+) (?\d+) / - * scanner.match?(pattern) - * scanner.values_at(*0..3) # => ["Fri Dec 12 ", "Fri", "Dec", "12"] - * scanner.values_at(*%i[wday month day]) # => ["Fri", "Dec", "12"] - * ``` + * Returns the subgroups in the most recent match at the given indices. + * If nothing was priorly matched, it returns nil. * + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.scan(/(\w+) (\w+) (\d+) /) # -> "Fri Dec 12 " + * s.values_at 0, -1, 5, 2 # -> ["Fri Dec 12 ", "12", nil, "Dec"] + * s.scan(/(\w+) (\w+) (\d+) /) # -> nil + * s.values_at 0, -1, 5, 2 # -> nil */ static VALUE @@ -2141,29 +1359,13 @@ strscan_values_at(int argc, VALUE *argv, VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * pre_match -> substring - * - * Returns the substring that precedes the matched substring - * from the most recent match attempt if it was successful, - * or `nil` otherwise; - * see [Basic Match Values][18]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.pre_match # => nil - * - * scanner.pos = 3 - * scanner.exist?(/baz/) # => 6 - * scanner.pre_match # => "foobar" # Substring of entire string, not just target string. - * - * scanner.exist?(/nope/) # => nil - * scanner.pre_match # => nil - * ``` + * Returns the pre-match (in the regular expression sense) of the last scan. * + * s = StringScanner.new('test string') + * s.scan(/\w+/) # -> "test" + * s.scan(/\s+/) # -> " " + * s.pre_match # -> "test" + * s.post_match # -> "string" */ static VALUE strscan_pre_match(VALUE self) @@ -2178,29 +1380,13 @@ strscan_pre_match(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * post_match -> substring - * - * Returns the substring that follows the matched substring - * from the most recent match attempt if it was successful, - * or `nil` otherwise; - * see [Basic Match Values][18]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.post_match # => nil - * - * scanner.pos = 3 - * scanner.match?(/bar/) # => 3 - * scanner.post_match # => "baz" - * - * scanner.match?(/nope/) # => nil - * scanner.post_match # => nil - * ``` + * Returns the post-match (in the regular expression sense) of the last scan. * + * s = StringScanner.new('test string') + * s.scan(/\w+/) # -> "test" + * s.scan(/\s+/) # -> " " + * s.pre_match # -> "test" + * s.post_match # -> "string" */ static VALUE strscan_post_match(VALUE self) @@ -2215,24 +1401,8 @@ strscan_post_match(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * rest -> target_substring - * - * Returns the 'rest' of the [stored string][1] (all after the current [position][2]), - * which is the [target substring][3]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.rest # => "foobarbaz" - * scanner.pos = 3 - * scanner.rest # => "barbaz" - * scanner.terminate - * scanner.rest # => "" - * ``` - * + * Returns the "rest" of the string (i.e. everything after the scan pointer). + * If there is no more data (eos? = true), it returns "". */ static VALUE strscan_rest(VALUE self) @@ -2247,26 +1417,7 @@ strscan_rest(VALUE self) } /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * rest_size -> integer - * - * Returns the size (in bytes) of the #rest of the [stored string][1]: - * - * ``` - * scanner = StringScanner.new('foobarbaz') - * scanner.rest # => "foobarbaz" - * scanner.rest_size # => 9 - * scanner.pos = 3 - * scanner.rest # => "barbaz" - * scanner.rest_size # => 6 - * scanner.terminate - * scanner.rest # => "" - * scanner.rest_size # => 0 - * ``` - * + * s.rest_size is equivalent to s.rest.size. */ static VALUE strscan_rest_size(VALUE self) @@ -2283,14 +1434,9 @@ strscan_rest_size(VALUE self) } /* - * call-seq: - * restsize - * * s.restsize is equivalent to s.rest_size. * This method is obsolete; use #rest_size instead. */ - - /* :nodoc: */ static VALUE strscan_restsize(VALUE self) { @@ -2301,39 +1447,15 @@ strscan_restsize(VALUE self) #define INSPECT_LENGTH 5 /* - * :markup: markdown - * :include: link_refs.txt - * - * call-seq: - * inspect -> string - * - * Returns a string representation of `self` that may show: - * - * 1. The current [position][2]. - * 2. The size (in bytes) of the [stored string][1]. - * 3. The substring preceding the current position. - * 4. The substring following the current position (which is also the [target substring][3]). - * - * ``` - * scanner = StringScanner.new("Fri Dec 12 1975 14:39") - * scanner.pos = 11 - * scanner.inspect # => "#" - * ``` - * - * If at beginning-of-string, item 4 above (following substring) is omitted: - * - * ``` - * scanner.reset - * scanner.inspect # => "#" - * ``` - * - * If at end-of-string, all items above are omitted: - * - * ``` - * scanner.terminate - * scanner.inspect # => "#" - * ``` + * Returns a string that represents the StringScanner object, showing: + * - the current position + * - the size of the string + * - the characters surrounding the scan pointer * + * s = StringScanner.new("Fri Dec 12 1975 14:39") + * s.inspect # -> '#' + * s.scan_until /12/ # -> "Fri Dec 12" + * s.inspect # -> '#' */ static VALUE strscan_inspect(VALUE self) @@ -2405,13 +1527,13 @@ inspect2(struct strscanner *p) } /* - * :markup: markdown - * :include: link_refs.txt - * * call-seq: - * fixed_anchor? -> true or false + * scanner.fixed_anchor? -> true or false * - * Returns whether the [fixed-anchor property][10] is set. + * Whether +scanner+ uses fixed anchor mode or not. + * + * If fixed anchor mode is used, +\A+ always matches the beginning of + * the string. Otherwise, +\A+ always matches the current position. */ static VALUE strscan_fixed_anchor_p(VALUE self) @@ -2447,32 +1569,14 @@ named_captures_iter(const OnigUChar *name, } /* - * :markup: markdown - * :include: link_refs.txt - * * call-seq: - * named_captures -> hash + * scanner.named_captures -> hash * - * Returns the array of captured match values at indexes (1..) - * if the most recent match attempt succeeded, or nil otherwise; - * see [Captured Match Values][13]: - * - * ``` - * scanner = StringScanner.new('Fri Dec 12 1975 14:39') - * scanner.named_captures # => {} - * - * pattern = /(?\w+) (?\w+) (?\d+) / - * scanner.match?(pattern) - * scanner.named_captures # => {"wday"=>"Fri", "month"=>"Dec", "day"=>"12"} - * - * scanner.string = 'nope' - * scanner.match?(pattern) - * scanner.named_captures # => {"wday"=>nil, "month"=>nil, "day"=>nil} - * - * scanner.match?(/nosuch/) - * scanner.named_captures # => {} - * ``` + * Returns a hash of string variables matching the regular expression. * + * scan = StringScanner.new('foobarbaz') + * scan.match?(/(?foo)(?bar)(?baz)/) + * scan.named_captures # -> {"f"=>"foo", "r"=>"bar", "z"=>"baz"} */ static VALUE strscan_named_captures(VALUE self) @@ -2496,11 +1600,109 @@ strscan_named_captures(VALUE self) /* * Document-class: StringScanner * - * :markup: markdown + * StringScanner provides for lexical scanning operations on a String. Here is + * an example of its usage: * - * :include: link_refs.txt - * :include: strscan.md + * require 'strscan' * + * s = StringScanner.new('This is an example string') + * s.eos? # -> false + * + * p s.scan(/\w+/) # -> "This" + * p s.scan(/\w+/) # -> nil + * p s.scan(/\s+/) # -> " " + * p s.scan(/\s+/) # -> nil + * p s.scan(/\w+/) # -> "is" + * s.eos? # -> false + * + * p s.scan(/\s+/) # -> " " + * p s.scan(/\w+/) # -> "an" + * p s.scan(/\s+/) # -> " " + * p s.scan(/\w+/) # -> "example" + * p s.scan(/\s+/) # -> " " + * p s.scan(/\w+/) # -> "string" + * s.eos? # -> true + * + * p s.scan(/\s+/) # -> nil + * p s.scan(/\w+/) # -> nil + * + * Scanning a string means remembering the position of a scan pointer, + * which is just an index. The point of scanning is to move forward a bit at + * a time, so matches are sought after the scan pointer; usually immediately + * after it. + * + * Given the string "test string", here are the pertinent scan pointer + * positions: + * + * t e s t s t r i n g + * 0 1 2 ... 1 + * 0 + * + * When you #scan for a pattern (a regular expression), the match must occur + * at the character after the scan pointer. If you use #scan_until, then the + * match can occur anywhere after the scan pointer. In both cases, the scan + * pointer moves just beyond the last character of the match, ready to + * scan again from the next character onwards. This is demonstrated by the + * example above. + * + * == Method Categories + * + * There are other methods besides the plain scanners. You can look ahead in + * the string without actually scanning. You can access the most recent match. + * You can modify the string being scanned, reset or terminate the scanner, + * find out or change the position of the scan pointer, skip ahead, and so on. + * + * === Advancing the Scan Pointer + * + * - #getch + * - #get_byte + * - #scan_byte + * - #scan + * - #scan_until + * - #skip + * - #skip_until + * + * === Looking Ahead + * + * - #check + * - #check_until + * - #exist? + * - #match? + * - #peek + * - #peek_byte + * + * === Finding Where we Are + * + * - #beginning_of_line? (#bol?) + * - #eos? + * - #rest? + * - #rest_size + * - #pos + * + * === Setting Where we Are + * + * - #reset + * - #terminate + * - #pos= + * + * === Match Data + * + * - #matched + * - #matched? + * - #matched_size + * - #[] + * - #pre_match + * - #post_match + * + * === Miscellaneous + * + * - << + * - #concat + * - #string + * - #string= + * - #unscan + * + * There are aliases to several of the methods. */ void Init_strscan(void)