diff options
Diffstat (limited to 'src/library/scala/CharSequence.scala')
-rw-r--r-- | src/library/scala/CharSequence.scala | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/library/scala/CharSequence.scala b/src/library/scala/CharSequence.scala new file mode 100644 index 0000000000..651650471c --- /dev/null +++ b/src/library/scala/CharSequence.scala @@ -0,0 +1,172 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2007, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: + + +package scala + +import java.io._ +import collection._ +import util.matching.Regex + +/** A Scala abstraction of character sequences, similar to, but richer than, + * java.lang.CharSequence. Sequences can be fixed or lazy. A lazy + * character sequence may be constructed only while it is read. + * + * @author Martin Odersky + */ +trait CharSequence extends java.lang.CharSequence with Seq[Char] { + + /** The length of the character sequence + * Note: if char sequence is lazy, calling this method + * will force sequence to be read until the end. + */ + def length: Int + + /** The character at position `index'. + */ + def charAt(index: Int): Char + + /** Is character sequence defined at `index'? + * Unlike `length' this operation does not force reading + * a lazy sequence to the end. + * (the implementation of that method is inherited from Seq). + */ + def isDefinedAt(index: Int): Boolean + + /** Optionally the character at position `index'. None is not in range. + */ + def get(index: Int): Option[Char] = + if (isDefinedAt(index)) Some(charAt(index)) + else None + + /** The character at position `index'. (same as `charAt') + */ + def apply(index: Int): Char = charAt(index) + + /** the subsequence from index `start' up to and excluding + * the minimum of index `end' and the length of current sequence. + */ + def subSequence(start: Int, end: Int): CharSequence + + /** The subsequence from index `start' until the end of the current sequence + * If sequence is lazy, this operation does not force reading to the end. + */ + def subSequence(start: Int): CharSequence = + subSequence(start, length) + + /** Convert sequence to string */ + def toString: String + + /** the elements of this sequence */ + def elements: Iterator[Char] = new Iterator[Char] { + private var index = 0 + def hasNext: Boolean = isDefinedAt(index) + def next: Char = { + val ch = charAt(index) + index += 1 + ch + } + } + + /** Return all matches of given regexp in this character sequence as an iterator + */ + def findAll(regex: Regex): Regex.MatchIterator = regex findAllIn this + + /** Return first match of given regexp in this character sequence as an optional value + */ + def findFirst(regex: Regex): Option[String] = regex findFirstIn this + + /** Return first match of given regexp in this character sequence as an optional value + */ + def findFirstMatch(regex: Regex): Option[Regex.Match] = regex findFirstMatchIn this + + /** Return optionally string matching given regexp at the beginning of this + * character sequence, or None if regexp matches no prefix + * of the character sequence. + */ + def findPrefix(regex: Regex): Option[String] = regex findPrefixOf this + + /** Return optionally match for given regexp at the beginning of this + * character sequence, or None if regexp matches no prefix + * of the character sequence. + */ + def findPrefixMatch(regex: Regex): Option[Regex.Match] = regex findPrefixMatchOf this + + /** Replaces all matches of given regexp by a string. + * + * @param regex The regex to match with + * @param replacement The string that will replace each match + * @return The resulting string + */ + def replaceAll(regex: Regex, replacement: String): String = regex replaceAllIn (this, replacement) + + /** Replaces the first match of given regexp by a string. + * + * @param target The string to match + * @param replacement The string that will replace the match + * @return The resulting string + */ + def replaceFirst(regex: Regex, replacement: String): String = regex replaceFirstIn (this, replacement) + + def toArray: Array[Char] = { + val len = length + val result = new Array[Char](len) + var i = 0 + while (i < len) { + result(i) = charAt(i) + i += 1 + } + result + } +} + +/** The CharSequence object defines variance implementations of character sequences + */ +object CharSequence { + + def fromJava(source: java.lang.CharSequence): CharSequence = + new JavaWrapper(source) + + def fromArray(source: Array[Char]): CharSequence = + new AsArray(source, 0, source.length) + def fromArray(source: Array[Char], start: Int): CharSequence = + new AsArray(source, start, source.length) + def fromArray(source: Array[Char], start: Int, end: Int): CharSequence = + new AsArray(source, start, end) + + private class JavaWrapper(source: java.lang.CharSequence) extends CharSequence { + def length: Int = source.length + def charAt(index: Int): Char = source.charAt(index) + def subSequence(start: Int, end: Int): CharSequence = new JavaWrapper(source.subSequence(start, end)) + override def toString: String = source.toString + } + + private class AsArray(source: scala.Array[Char], start: Int, end: Int) extends CharSequence { + if (start < 0) throw new IndexOutOfBoundsException + if (end > source.length) throw new IndexOutOfBoundsException + + def charAt(index: Int) = + if (start + index < end) source(index + start) + else throw new IndexOutOfBoundsException + + def length: Int = if (end < start) 0 else end - start + + def subSequence(_start: Int, _end: Int) = + new AsArray(source, start + _start, start + _end) + + override def toArray: Array[Char] = { + val result = new Array[Char](length) + compat.Platform.arraycopy(source, start, result, 0, length) + result + } + + override def toString = new String(source, start, end - start) + } +} |