You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by py...@apache.org on 2006/07/25 08:18:32 UTC
svn commit: r425299 - in
/incubator/harmony/enhanced/classlib/trunk/modules/luni/src:
main/java/java/util/Scanner.java
test/java/tests/api/java/util/ScannerTest.java
Author: pyang
Date: Mon Jul 24 23:18:31 2006
New Revision: 425299
URL: http://svn.apache.org/viewvc?rev=425299&view=rev
Log:
Fix for HARMONY-967 ([classlib][luni] Implementation of java.util.Scanner.findInLine())
Modified:
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java?rev=425299&r1=425298&r2=425299&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java Mon Jul 24 23:18:31 2006
@@ -56,34 +56,54 @@
*/
public final class Scanner implements Iterator<String> {
- // Default delimiting pattern
+ // Default delimiting pattern.
private static final Pattern DEFAULT_DELIMITER = Pattern
.compile("\\p{javaWhitespace}+"); //$NON-NLS-1$
- //The boolean's pattern
+ // The boolean's pattern.
private static final Pattern BOOLEAN_PATTERN = Pattern.compile(
"true|false", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
- // Pattern used to recognize line terminator
- private static final Pattern LINE_TERMINATOR = Pattern
- .compile("\n|\r\n|\r|\u0085|\u2028|\u2029"); //$NON-NLS-1$
+ // Pattern used to recognize line terminator.
+ private static final Pattern LINE_TERMINATOR;
+
+ // Pattern used to recognize multiple line terminators.
+ private static final Pattern MULTI_LINE_TERMINATOR;
+
// Pattern used to recognize a line with a line terminator.
- private static final Pattern LINE_PATTERN = Pattern
- .compile(".*(" + LINE_TERMINATOR.pattern() + //$NON-NLS-1$
- ")|.+(" + LINE_TERMINATOR.pattern() + ")?"); //$NON-NLS-1$ //$NON-NLS-2$
+ private static final Pattern LINE_PATTERN;
+
+ static {
+ String terminator = "\n|\r\n|\r|\u0085|\u2028|\u2029"; //$NON-NLS-1$
+
+ LINE_TERMINATOR = Pattern.compile(terminator);
+
+ StringBuilder multiTerminator = new StringBuilder();
+ MULTI_LINE_TERMINATOR = Pattern
+ .compile(multiTerminator.append("(") //$NON-NLS-1$
+ .append(terminator)
+ .append(")+").toString()); //$NON-NLS-1$
+ StringBuilder line = new StringBuilder();
+ LINE_PATTERN = Pattern
+ .compile(line.append(".*(") //$NON-NLS-1$
+ .append(terminator)
+ .append(")|.+(") //$NON-NLS-1$
+ .append(terminator)
+ .append(")?").toString()); //$NON-NLS-1$
+ }
- // The pattern matching anything
+ // The pattern matches anything.
private static final Pattern ANY_PATTERN = Pattern.compile("(?s).*"); //$NON-NLS-1$
private static final int DIPLOID = 2;
- // Default radix
+ // Default radix.
private static final int DEFAULT_RADIX = 10;
private static final int DEFAULT_TRUNK_SIZE = 1024;
- // The input source of scanner
+ // The input source of scanner.
private Readable input;
private CharBuffer buffer;
@@ -96,16 +116,17 @@
private Locale locale = Locale.getDefault();
- // The position where find begins
+ // The position where find begins.
private int findStartIndex = 0;
- // The last find start position
+ // The last find start position.
private int preStartIndex = findStartIndex;
- // The length of the buffer
+ // The length of the buffer.
private int bufferLength = 0;
- // Used by find and nextXXX operation
+ // Record the status of this scanner. True if the scanner
+ // is closed.
private boolean closed = false;
private IOException lastIOException;
@@ -114,7 +135,7 @@
private DecimalFormat decimalFormat;
- // Records whether the underlying readable has more input
+ // Records whether the underlying readable has more input.
private boolean inputExhausted = false;
private enum DataType{
@@ -306,14 +327,98 @@
return delimiter;
}
- //TODO: To implement this feature
+ /**
+ * Tries to find the pattern in input. Delimiters are ignored. If the
+ * pattern is found before line terminator, the matched string will be
+ * returned, and the scanner will advance to the end of the matched string.
+ * Otherwise, null will be returned and the scanner will not advance the
+ * input. When waiting for input, the scanner may be blocked.
+ *
+ * All the input may be cached if no line terminator exists in the buffer.
+ *
+ * @param pattern
+ * the pattern used to match input
+ * @return the matched string
+ * @throws IllegalStateException
+ * if the scanner is closed
+ */
public String findInLine(Pattern pattern) {
- throw new NotYetImplementedException();
+ checkClosed();
+ checkNull(pattern);
+ int horizonLineSeparator = 0;
+
+ matcher.usePattern(MULTI_LINE_TERMINATOR);
+ matcher.region(findStartIndex, bufferLength);
+
+ boolean findComplete = false;
+ int terminatorLength = 0;
+ while (!findComplete) {
+ if (matcher.find()) {
+ horizonLineSeparator = matcher.start();
+ terminatorLength = matcher.end() - matcher.start();
+ findComplete = true;
+ } else {
+ if (!inputExhausted) {
+ readMore();
+ resetMatcher();
+ } else {
+ horizonLineSeparator = bufferLength;
+ findComplete = true;
+ }
+ }
+ }
+
+ matcher.usePattern(pattern);
+
+ /*
+ * TODO The following 2 statements are used to deal with regex's
+ * bug. java.util.regex.Matcher.region(int start, int end)
+ * implementation does not have any effects when called. They will be
+ * removed once the bug is fixed.
+ */
+ int oldLimit = buffer.limit();
+ buffer.limit(horizonLineSeparator);
+ // ========== To deal with regex bug ====================
+
+ matcher.region(findStartIndex, horizonLineSeparator);
+ if (matcher.find()) {
+ // The scanner advances past the input that matched
+ findStartIndex = matcher.end();
+ // If the matched pattern is immediately followed by line terminator.
+ if(horizonLineSeparator == matcher.end()) {
+ findStartIndex += terminatorLength;
+ }
+ matchSuccessful = true;
+
+ // ========== To deal with regex bug ====================
+ buffer.limit(oldLimit);
+ // ========== To deal with regex bug ====================
+
+ return matcher.group();
+ }
+
+ // ========== To deal with regex bug ====================
+ buffer.limit(oldLimit);
+ // ========== To deal with regex bug ====================
+
+ matchSuccessful = false;
+ return null;
}
- //TODO: To implement this feature
+ /**
+ * Tries to find the pattern compiled from the specified string. The
+ * delimiter will be ignored. It is the same as invoke
+ * findInLine(Pattern.compile(pattern))
+ *
+ * @param pattern
+ * a string used to construct a pattern which in turn used to
+ * match input
+ * @return the matched string
+ * @throws IllegalStateException
+ * if the scanner is closed
+ */
public String findInLine(String pattern) {
- throw new NotYetImplementedException();
+ return findInLine(Pattern.compile(pattern));
}
/**
@@ -970,8 +1075,6 @@
* locale specific negative prefixes and suffixes were present. At last the
* resulting String is passed to {@link BigDecimal#BigDecimal(String)}}.
*
- * @param integerRadix
- * the radix used to translate the token into BigDecimal
* @return the BigDecimal scanned from the input
* @throws IllegalStateException
* if this scanner has been closed
@@ -1624,7 +1727,7 @@
* The operation of remove is not supported by this implementation of
* Iterator.
*
- * @return UnsupportedOperationException
+ * @throw UnsupportedOperationException
* if this method is invoked
*/
public void remove() {
@@ -2060,9 +2163,9 @@
*/
private void readMore() {
int oldPosition = buffer.position();
- int oldLimit = buffer.limit();
+ int oldBufferLength = bufferLength;
// Increase capacity if empty space is not enough
- if (buffer.limit() >= buffer.capacity()) {
+ if (bufferLength >= buffer.capacity()) {
expandBuffer();
}
@@ -2070,7 +2173,7 @@
int readCount = 0;
try {
buffer.limit(buffer.capacity());
- buffer.position(oldLimit);
+ buffer.position(oldBufferLength);
while ((readCount = input.read(buffer)) == 0) {
// nothing to do here
}
@@ -2078,7 +2181,7 @@
// Consider the scenario: readable puts 4 chars into
// buffer and then an IOException is thrown out. In this case, buffer is
// actually grown, but readable.read() will never return.
- bufferLength += (buffer.position() - oldLimit);
+ bufferLength = buffer.position();
/*
* Uses -1 to record IOException occurring, and no more input can be
* read.
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java?rev=425299&r1=425298&r2=425299&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java Mon Jul 24 23:18:31 2006
@@ -699,10 +699,10 @@
// Harmony uses 1024 as default buffer size,
// What if a sentence can not be read in all in once.
StringBuilder longSentence = new StringBuilder(1025);
- for (int i = 0; i <= 10; i++) {
+ for (int i = 0; i < 11; i++) {
longSentence.append(" ");
}
- for (int i = 11; i <= 1025; i++) {
+ for (int i = 11; i < 1026; i++) {
longSentence.append("a");
}
s = new Scanner(longSentence.toString());
@@ -4814,6 +4814,159 @@
s = new Scanner("aaaa");
result = s.findWithinHorizon(Pattern.compile("a*"), 0);
assertEquals("aaaa", result);
+ }
+
+ /**
+ * @tests java.util.Scanner#findInLine(Pattern)
+ */
+ public void test_findInLine_LPattern() {
+
+ Scanner s = new Scanner("");
+ try {
+ s.findInLine((Pattern) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ String result = s.findInLine(Pattern.compile("^"));
+ assertEquals("", result);
+ MatchResult matchResult = s.match();
+ assertEquals(0, matchResult.start());
+ assertEquals(0, matchResult.end());
+
+ result = s.findInLine(Pattern.compile("$"));
+ assertEquals("", result);
+ matchResult = s.match();
+ assertEquals(0, matchResult.start());
+ assertEquals(0, matchResult.end());
+
+ /*
+ * When we use the operation of findInLine(Pattern), the match region
+ * should not span the line separator.
+ */
+ s = new Scanner("aa\nb.b");
+ result = s.findInLine(Pattern.compile("a\nb*"));
+ assertNull(result);
+
+ s = new Scanner("aa\nbb.b");
+ result = s.findInLine(Pattern.compile("\\."));
+ assertNull(result);
+
+ s = new Scanner("abcd1234test\n");
+ result = s.findInLine(Pattern.compile("\\p{Lower}+"));
+ assertEquals("abcd", result);
+ matchResult = s.match();
+ assertEquals(0, matchResult.start());
+ assertEquals(4, matchResult.end());
+
+ result = s.findInLine(Pattern.compile("\\p{Digit}{5}"));
+ assertNull(result);
+ try {
+ matchResult = s.match();
+ fail("Should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ assertEquals(0, matchResult.start());
+ assertEquals(4, matchResult.end());
+
+ result = s.findInLine(Pattern.compile("\\p{Lower}+"));
+ assertEquals("test", result);
+ matchResult = s.match();
+ assertEquals(8, matchResult.start());
+ assertEquals(12, matchResult.end());
+
+ char[] chars = new char[2048];
+ Arrays.fill(chars, 'a');
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(chars);
+ stringBuilder.append("1234");
+ s = new Scanner(stringBuilder.toString());
+ result = s.findInLine(Pattern.compile("\\p{Digit}+"));
+ assertEquals("1234", result);
+ matchResult = s.match();
+ assertEquals(2048, matchResult.start());
+ assertEquals(2052, matchResult.end());
+
+ s = new Scanner("test");
+ s.close();
+ try {
+ s.findInLine((Pattern) null);
+ fail("Should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // expected
+ }
+
+ s = new Scanner("test1234\n1234 test");
+ result = s.findInLine(Pattern.compile("test"));
+ assertEquals("test", result);
+ matchResult = s.match();
+ assertEquals(0, matchResult.start());
+ assertEquals(4, matchResult.end());
+
+ int number = s.nextInt();
+ assertEquals(1234, number);
+ matchResult = s.match();
+ assertEquals(4, matchResult.start());
+ assertEquals(8, matchResult.end());
+
+ result = s.next();
+ assertEquals("1234", result);
+ matchResult = s.match();
+ assertEquals(9, matchResult.start());
+ assertEquals(13, matchResult.end());
+
+ result = s.findInLine(Pattern.compile("test"));
+ assertEquals("test", result);
+ matchResult = s.match();
+ assertEquals(14, matchResult.start());
+ assertEquals(18, matchResult.end());
+
+ s = new Scanner("test\u0085\ntest");
+ result = s.findInLine("est");
+ assertEquals("est", result);
+ result = s.findInLine("est");
+ assertEquals("est", result);
+
+ s = new Scanner("test\ntest");
+ result = s.findInLine("est");
+ assertEquals("est", result);
+ result = s.findInLine("est");
+ assertEquals("est", result);
+
+ s = new Scanner("test\n123\ntest");
+ result = s.findInLine("est");
+ assertEquals("est", result);
+ result = s.findInLine("est");
+ // RI fails. It is a RI's bug.
+ assertNull(result);
+ }
+
+ /**
+ * @tests java.util.Scanner#findInLine(String)
+ */
+ public void test_findInLine_LString() {
+ s = new Scanner("test");
+ try {
+ s.findInLine((String) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ s.close();
+ try {
+ s.findInLine((String) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ try {
+ s.findInLine("test");
+ fail("Should throw IllegalStateException");
+ } catch (IllegalStateException e) {
+ // exptected
+ }
}
/**