Class: StringScanner

Inherits:
Object show all
Defined in:
lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb

Overview

StringScanner provides for lexical scanning operations on a String. Here is an example of its usage:

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

  • #scan_until

  • #skip

  • #skip_until

Looking Ahead

  • #check

  • #check_until

  • #exist?

  • #match?

  • #peek

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.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(string, dup = false) ⇒ StringScanner

StringScanner.new(string, dup = false)

Creates a new StringScanner object to scan over the given string. dup argument is obsolete and not used now.



141
142
143
144
145
146
147
148
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 141

def initialize(string, dup = false)
  begin
    @string = string.to_str
  rescue
    raise TypeError, "can't convert #{string.class.name} into String"
  end
  @pos = 0
end

Instance Attribute Details

#posObject Also known as: pointer

string <String>

The string to scan

pos <Integer>

The 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 length of the string.

In short, it's a 0-based index into the string.

  s = StringScanner.new('test string')
  s.pos               # -> 0
  s.scan_until /str/  # -> "test str"
  s.pos               # -> 8
  s.terminate         # -> #<StringScanner fin>
  s.pos               # -> 11
match <String>

Matched string



128
129
130
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 128

def pos
  @pos
end

#stringObject

string <String>

The string to scan

pos <Integer>

The 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 length of the string.

In short, it's a 0-based index into the string.

  s = StringScanner.new('test string')
  s.pos               # -> 0
  s.scan_until /str/  # -> "test str"
  s.pos               # -> 8
  s.terminate         # -> #<StringScanner fin>
  s.pos               # -> 11
match <String>

Matched string



128
129
130
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 128

def string
  @string
end

Class Method Details

.must_C_versionObject

This method is defined for backward compatibility.



132
133
134
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 132

def self.must_C_version
  self
end

Instance Method Details

#[](n) ⇒ Object

Return the n-th subgroup in the most recent match.

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                        # -> ""

Raises:

  • (TypeError)


597
598
599
600
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 597

def [](n)
  raise TypeError, "Bad argument #{n.inspect}" unless n.respond_to? :to_int
  @match.nil? ? nil : @match[n]
end

#bol?Boolean Also known as: beginning_of_line?

Returns true iff the scan pointer is at the beginning of the 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

Returns:

  • (Boolean)


581
582
583
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 581

def bol?
  (@pos == 0) || (@string[@pos-1] == "\n")
end

#check(pattern) ⇒ Object

This returns the value that #scan would return, without advancing the scan pointer. The match register is affected, though.

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.



498
499
500
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 498

def check(pattern)
  _scan(pattern, false, true, true)
end

#check_until(pattern) ⇒ Object

This returns the value that #scan_until would return, without advancing the scan pointer. The match register is affected, though.

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.



513
514
515
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 513

def check_until(pattern)
  _scan(pattern, false, true, false)
end

#clearObject

Equivalent to #terminate. This method is obsolete; use #terminate instead.



178
179
180
181
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 178

def clear
  warn "StringScanner#clear is obsolete; use #terminate instead" if $VERBOSE
  terminate
end

#concat(str) ⇒ Object Also known as: <<

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"


204
205
206
207
208
209
210
211
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 204

def concat(str)
  begin
    @string << str.to_str
  rescue
    raise TypeError, "can't convert #{str.class.name} into String"
  end
  self
end

#empty?Boolean

Equivalent to #eos?. This method is obsolete, use #eos? instead.

Returns:

  • (Boolean)


335
336
337
338
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 335

def empty?
  warn "StringScanner#empty? is obsolete; use #eos? instead" if $VERBOSE
  eos?
end

#eos?Boolean

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

Returns:

  • (Boolean)


328
329
330
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 328

def eos?
  @pos >= @string.size
end

#exist?(pattern) ⇒ Boolean

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/            # -> 6
s.exist? /e/            # -> nil

Returns:

  • (Boolean)


527
528
529
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 527

def exist?(pattern)
  _scan(pattern, false, false, false)
end

#get_byteObject

Scans one byte and returns it. This method is not multibyte sensitive. See also: #getch.

s = StringScanner.new('ab')
s.get_byte         # => "a"
s.get_byte         # => "b"
s.get_byte         # => nil

# encoding: EUC-JP
s = StringScanner.new("\244\242")
s.get_byte         # => "244"
s.get_byte         # => "242"
s.get_byte         # => nil


244
245
246
247
248
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 244

def get_byte
  # temp hack
  # TODO replace by a solution that will work with UTF-8
  scan(/./mn)
end

#getbyteObject

Equivalent to #get_byte. This method is obsolete; use #get_byte instead.



253
254
255
256
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 253

def getbyte
  warn "StringScanner#getbyte is obsolete; use #get_byte instead" if $VERBOSE
  get_byte
end

#getchObject

Scans one character and returns it. This method is multibyte character sensitive.

s = StringScanner.new("ab")
s.getch           # => "a"
s.getch           # => "b"
s.getch           # => nil


315
316
317
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 315

def getch
  scan(/./m)
end

#initialize_copy(orig) ⇒ Object

Duplicates a StringScanner object when dup or clone are called on the object.



153
154
155
156
157
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 153

def initialize_copy(orig)
  @string = orig.string
  @pos = orig.pos
  @match = orig.instance_variable_get("@match")
end

#inspectObject

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 # -> ‘#<StringScanner 0/21 @ “Fri D…”>’ s.scan_until /12/ # -> “Fri Dec 12” s.inspect # -> ‘#<StringScanner 10/21 “…ec 12” @ “ 1975…”>’



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 382

def inspect
  if defined?(@string)
    rest = @string.size > 5 ? @string[@pos..@pos+4] + "..." : @string
    to_return =  if eos? then
                  "#<StringScanner fin>"
                elsif pos > 0 then
                  prev = @string[0...@pos].inspect
                  "#<StringScanner #{@pos}/#{@string.size} #{prev} @ #{rest.inspect}>"
                else
                  "#<StringScanner #{@pos}/#{@string.size} @ #{rest.inspect}>"
                end
    to_return.taint if @string.tainted?
    to_return
  else
    "#<StringScanner (uninitialized)>"
  end
end

#match?(pattern) ⇒ Boolean

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?(/\s+/)   # -> nil

Returns:

  • (Boolean)


408
409
410
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 408

def match?(pattern)
  _scan(pattern, false, false, true)
end

#matchedObject

Returns the last matched string.

s = StringScanner.new('test string')
s.match?(/\w+/)     # -> 4
s.matched           # -> "test"


418
419
420
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 418

def matched
  @match.to_s if matched?
end

#matched?Boolean

Returns true iff the last match was successful.

s = StringScanner.new('test string')
s.match?(/\w+/)     # => 4
s.matched?          # => true
s.match?(/\d+/)     # => nil
s.matched?          # => false

Returns:

  • (Boolean)


430
431
432
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 430

def matched?
  !@match.nil?
end

#matched_sizeObject

Returns the last matched string.

s = StringScanner.new('test string')
s.match?(/\w+/)     # -> 4
s.matched           # -> "test"


440
441
442
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 440

def matched_size
  @match.to_s.size if matched?
end

#matchedsizeObject

Equivalent to #matched_size. This method is obsolete; use #matched_size instead.



447
448
449
450
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 447

def matchedsize
  warn "StringScanner#matchedsize is obsolete; use #matched_size instead" if $VERBOSE
  matched_size
end

#peek(length) ⇒ Object

Extracts a string corresponding to string[pos,len], without advancing the scan pointer.

s = StringScanner.new('test string')
s.peek(7)          # => "test st"
s.peek(7)          # => "test st"

Raises:

  • (TypeError)


538
539
540
541
542
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 538

def peek(length)
  raise TypeError, "can't convert #{length.class.name} into Integer" unless length.respond_to?(:to_int)
  raise ArgumentError if length < 0
  length.zero? ? "" :  @string[@pos, length]
end

#peep(length) ⇒ Object

Equivalent to #peek. This method is obsolete; use #peek instead.



547
548
549
550
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 547

def peep(length)
  warn "StringScanner#peep is obsolete; use #peek instead" if $VERBOSE
  peek(length)
end

#post_matchObject

Return 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"


625
626
627
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 625

def post_match
  @match.post_match if matched?
end

#pre_matchObject

Return 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"


610
611
612
613
614
615
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 610

def pre_match
  if matched?
    p = @string.size - @match.string.size + @match.begin(0)
    @string[0...p]
  end
end

#resetObject

Reset the scan pointer (index 0) and clear matching data.



161
162
163
164
165
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 161

def reset
  @pos = 0
  @match = nil
  self
end

#restObject

Returns the “rest” of the string (i.e. everything after the scan pointer). If there is no more data (eos? = true), it returns "".



354
355
356
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 354

def rest
  @string[@pos..-1] || ""
end

#rest?Boolean

Returns true iff there is more data in the string. See #eos?. This method is obsolete; use #eos? instead.

s = StringScanner.new('test string')
s.eos?              # These two
s.rest?             # are opposites.

Returns:

  • (Boolean)


347
348
349
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 347

def rest?
  !eos?
end

#rest_sizeObject

s.rest_size is equivalent to s.rest.size.



360
361
362
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 360

def rest_size
  @string.size - @pos
end

#restsizeObject

s.restsize is equivalent to s.rest_size. This method is obsolete; use #rest_size instead.



367
368
369
370
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 367

def restsize
  warn "StringScanner#restsize is obsolete; use #rest_size instead" if $VERBOSE
  rest_size
end

#scan(pattern) ⇒ Object

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.

s = StringScanner.new('test string')
p s.scan(/\w+/)   # -> "test"
p s.scan(/\w+/)   # -> nil
p s.scan(/\s+/)   # -> " "
p s.scan(/\w+/)   # -> "string"
p s.scan(/./)     # -> nil


269
270
271
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 269

def scan(pattern)
  _scan(pattern, true, true, true)
end

#scan_full(pattern, succptr, getstr) ⇒ Object

Tests whether the given pattern is matched from the current scan pointer. Returns the matched string if return_string_p is true. Advances the scan pointer if advance_pointer_p is true. The match register is affected.

“full” means “#scan with full parameters”.



293
294
295
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 293

def scan_full(pattern, succptr, getstr)
  _scan(pattern, succptr, getstr, true)
end

#scan_until(pattern) ⇒ Object

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


282
283
284
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 282

def scan_until(pattern)
  _scan(pattern, true, true, false)
end

#search_full(pattern, succptr, getstr) ⇒ Object

Scans the string until the pattern is matched. Returns the matched string if return_string_p is true, otherwise returns the number of bytes advanced. Advances the scan pointer if advance_pointer_p, otherwise not. This method does affect the match register.



303
304
305
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 303

def search_full(pattern, succptr, getstr)
  _scan(pattern, succptr, getstr, false)
end

#skip(pattern) ⇒ Object

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.

It’s similar to #scan, but without returning the matched string.

s = StringScanner.new('test string')
p s.skip(/\w+/)   # -> 4
p s.skip(/\w+/)   # -> nil
p s.skip(/\s+/)   # -> 1
p s.skip(/\w+/)   # -> 6
p s.skip(/./)     # -> nil


465
466
467
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 465

def skip(pattern)
  _scan(pattern, true, false, true)
end

#skip_until(pattern) ⇒ Object

Advances the scan pointer until pattern is matched and consumed. Returns the number of bytes advanced, or nil if no match was found.

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.

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


482
483
484
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 482

def skip_until(pattern)
  _scan(pattern, true, false, false)
end

#terminateObject

Set the scan pointer to the end of the string and clear matching data.



169
170
171
172
173
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 169

def terminate
  @match = nil
  @pos = @string.size
  self
end

#unscanObject

Set 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

Raises:



562
563
564
565
566
567
568
# File 'lib/motion-bundler/mocks/mac_ruby-0.12/strscan.rb', line 562

def unscan
  raise(ScanError, "unscan failed: previous match record not exist") if @match.nil?
  @pos = @prev_pos
  @prev_pos = nil
  @match = nil
  self
end