Permalink
Browse files

first commit

  • Loading branch information...
0 parents commit ce885ad498e95510f4aa216864dd48617e491b18 @michaelficarra committed Apr 29, 2011
Showing with 668 additions and 0 deletions.
  1. +24 −0 LICENSE
  2. +323 −0 README.md
  3. +160 −0 lib/StringScanner.js
  4. +33 −0 package.json
  5. +128 −0 src/StringScanner.coffee
24 LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2010-2011, Michael Ficarra
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the project nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall the copyright holder be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages (including,
+but not limited to, procurement of substitute goods or services; loss of use,
+data, or profits; or business interruption) however caused and on any theory of
+liability, whether in contract, strict liability, or tort (including negligence
+or otherwise) arising in any way out of the use of this software, even if
+advised of the possibility of such damage.
323 README.md
@@ -0,0 +1,323 @@
+StringScanner
+=============
+
+StringScanner performs lexical scanning operations on a string.
+Inspired by [Ruby's StringScanner class](http://ruby-doc.org/core/classes/StringScanner.html)
+
+
+How To Use
+----------
+
+Instantiate a new `StringScanner` by passing its constructor the string to scan.
+
+ var StringScanner = require("stringscanner");
+ var ss = new StringScanner("abc123 def456");
+ // #<StringScanner 0/13 @ "abc12...">
+
+For the following examples, `ss` represents the `StringScanner` instance
+defined above.
+
+### bol / beginningOfLine
+Returns `true` if the scan pointer is at the beginning of a line (right after
+`\n`) or the beginning of the string, `false` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.pointer() // 0
+ ss.bol() // true
+ ss.scan(/./) // "a"
+ ss.pointer() // 1
+ ss.bol() // false
+
+### captures
+Returns an Array containing the contents of the capturing groups in the last
+evaluated pattern match.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.check(/.*(..) (..)/ // "abc123 de"
+ ss.captures() // ["23","de"]
+ ss.check(/\w+/) // "abc123"
+ ss.captures() // []
+ ss.check(/\s+/) // null
+ ss.captures() // []
+
+
+### check(pattern)
+*Note: this method alters last match results*
+
+Checks if a `scan` of the given pattern would succeed without advancing the
+scan pointer. Returns the portion of the string matched on successful match,
+`null` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.check(/[a-z]+/i) // "abc"
+ ss.check(/[a-z]+/i) // "abc"
+ ss.scan(/[a-z]+/i) // "abc"
+ ss.check(/[a-z]+/i) // null
+ ss.check(/[\d\s]+/) // "123 "
+
+### checkUntil(pattern)
+*Note: this method alters last match results*
+
+Checks if a `scanUntil` would succeed without advancing the scan pointer.
+Returns the portion of the string being scanned from the scan pointer to the
+end of the matched string on successful match, `null` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.checkUntil(/\s/) // "abc123 "
+ ss.checkUntil(/\s/) // "abc123 "
+ ss.checkUntil(/r/) // null
+ ss.scanUntil(/e/) // "abc123 de"
+ ss.checkUntil(/\s/) // null
+
+### clone / dup
+Creates a duplicate of this instance of `StringScanner`.
+
+### concat(str)
+Appends the given string to the string being scanned.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.checkUntil(/h/) // null
+ ss.concat(" ghi789") // #<StringScanner 0/20 @ "abc12..."
+ ss.checkUntil(/h/) // "abc123 def456 gh"
+
+### eos / endOfstring
+Returns `true` if the scan pointer is at the end of the string being scanned,
+`false` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.pointer() // 0
+ ss.eos() // false
+ ss.scan(/.*/) // "abc123 def456"
+ ss.pointer() // 13
+ ss.eos() // true
+
+### exists(pattern) / exist(pattern)
+*Note: this method alters last match results*
+
+*Warning: this method may return `0` on a successful operation. Use `===`
+comparision to `null` for failure check, for example: `ss.exists(/a/i)===null`*
+
+Checks if the given pattern matches anywhere after the current scan pointer.
+This will determine if a `scanUntil` operation will succeed. Returns the
+number of characters between the scan pointer and the position in which the
+match was found on success, `null` otherwise.
+
+ ss.reset()
+ // ----
+ ss.exists(/c/) // 2
+ ss.match() // "c"
+ ss.matched() // true
+ // ----
+ ss.exists(/a/) // 0
+ ss.match() // "a"
+ ss.matched() // true
+ // ----
+ ss.exists(/b*/) // 0
+ ss.match() // ""
+ ss.matched() // true
+ // ----
+ ss.exists(/m/) // null
+ ss.match() // null
+ ss.matched() // false
+
+### getch / getChar
+*Note: this method alters last match results*
+
+*Note: Ruby equivalent: `get_byte`*
+
+`scan`s one character and returns it; exactly equivalent to `scan(/./)`.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.getch() // "a"
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scan(/./) // "a"
+
+### match
+*Note: Ruby equivalent: `matched`*
+
+Returns the last string matched or `null` if the last attempted match failed.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scan(/[a-z]+/i) // "abc"
+ ss.match() // "abc"
+ ss.check(/[a-z]+/i) // null
+ ss.match() // null
+
+### matches(pattern)
+*Note: Ruby equivalent: `match?`*
+
+Checks if a scan of the given pattern would succeed without advancing the scan
+pointer. Returns the length of the string matched on successful match, `null`
+otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.matches(/[a-z]+/i) // 3
+ ss.matches(/[a-z]+/i) // 3
+ ss.scan(/[a-z]+/i) // "abc"
+ ss.matches(/[a-z]+/i) // null
+ ss.matches(/[\d\s]+/) // 4
+
+### matched
+*Note: Ruby equivalent: `matched?`*
+
+Returns `true` if the last attempted match was successful, `false` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scan(/\w+/) // "abc123"
+ ss.matched() // true
+ ss.scan(/\w+/) // null
+ ss.matched() // false
+
+### matchSize
+*Warning: this method may return `0` on a successful operation. Use `===`
+comparision to `null` for failure check, for example: `ss.matchSize()===null`*
+
+Returns the length of the most recently matched string if the most recent match
+attempt succeeded, `null` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scan(/\w+/) // "abc123"
+ ss.matchSize() // 6
+ ss.check(/\w*/) // ""
+ ss.matchSize() // 0
+ ss.check(/\w+/) // null
+ ss.matchSize() // null
+
+### peek(len)
+Returns *len* characters after the scan pointer, or the rest of the string,
+whichever is shorter.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scan(/.*d/) // "abc123 d"
+ ss.peek(3) // "ef4"
+ ss.peek(9001) // "ef456"
+ ss.peek(0) // ""
+ ss.peek(-3) // ""
+
+### pointer / position
+Returns the scan pointer position as an integer.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.pointer() // 0
+ ss.scan(/\w+\d+\s+/) // "abc123 "
+ ss.pointer() // 7
+ ss.scan([a-z]+) // "def"
+ ss.pointer() // 10
+
+### setPointer(pos)
+Manually move the scan pointer to *pos* characters from the beginning of the
+string. The scan pointer is bounded between zero and the scanning string's
+length. Returns the position to which the scan pointer was moved. `setPointer`
+neither resets nor modifies the last match results.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.setPointer(4) // 4
+ ss.scan(/\d+/) // "23"
+ ss.pointer() // 6
+ ss.setPointer(-4) // 0
+ ss.setPointer(99) // 13
+
+### reset
+Moves the scan pointer back to the beginning of the string being scanned and
+clears the last match results.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scanUntil(/(\s)/) // "abc123 "
+ ss.pointer() // 7
+ ss.match() // "abc123 "
+ ss.captures() // [" "]
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.pointer() // 0
+ ss.match() // null
+ ss.captures() // []
+
+### rest
+Returns the portion of the string being scanned after the scan pointer.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scanUntil(/\s/) // "abc123 "
+ ss.rest() // "def456"
+
+### scan(pattern)
+*Note: this method alters last match results*
+
+Attempts to match the given pattern at the position of the scan pointer.
+Returns the matched string and advances the string pointer upon successful
+match. A failed match will result in a `null` value being returned.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scan(/[a-z]+/) // "abc"
+ ss // #<StringScanner 3/13 @ "abc12...">
+ ss.scan(/[a-z]+/) // null
+ ss // #<StringScanner 3/13 @ "abc12...">
+ ss.scan(/[0-9]+/) // "123"
+ ss // #<StringScanner 6/13 @ "abc12...">
+
+### scanUntil(pattern)
+*Note: this method alters last match results*
+
+Attempts to match the pattern against the string being scanned. On a successful
+match, the scan pointer is advanced to the end of the matched portion of the
+string and the portion of the string being scanned up to and including the
+matched string is returned. On a failed match, `null` is returned.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.scanUntil(/ /) // "abc123 "
+ ss.scanUntil(/f/) // "def"
+ ss.scanUntil(/f/) // null
+
+### skip(pattern)
+*Note: this method alters last match results*
+
+Performs a `scan`, returning the length of the matched string on successful
+match, `null` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.skip(/[a-z]+/) // 3
+ ss.skip(/[a-z]+/) // null
+ ss.skip(/[0-9]+/) // 3
+
+### skipUntil(pattern)
+*Note: this method alters last match results*
+
+Performs a `scanUntil`, returning the length of the matched string on
+successful match, `null` otherwise.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.skipUntil(/ /) // 7
+ ss.skipUntil(/f/) // 3
+ ss.skipUntil(/f/) // null
+
+### string
+Returns the entire string being scanned.
+
+ ss.string() // "abc123 def456"
+ ss.getch() // "a"
+ ss.string() // "abc123 def456"
+
+### terminate / clear
+Advances the scan pointer to the end of the string being scanned and resets the
+last match results.
+
+ ss.reset() // #<StringScanner 0/13 @ "abc12...">
+ ss.getch() // "a"
+ ss.pointer() // 1
+ ss.terminate() // #<StringScanner fin>
+ ss.pointer() // 13
+ ss.eos() // true
+ ss.match() // null
+
+Known Issues
+------------
+
+Not really an issue, but `StringScanner` assumes the global flag (g) is
+disabled on any RegExp objects passed as patterns to any of its methods. If the
+global flag is enabled, `StringScanner` may produce unexpected results.
+
+Additional Info
+---------------
+
+I am always open for feature requests or any feedback. I can be reached at
+[Github](http://github.com/michaelficarra).
+
+Thanks to the Ruby community for the original idea and implementation.
Oops, something went wrong.

0 comments on commit ce885ad

Please sign in to comment.