Skip to content

Commit

Permalink
Added a StringLineIterator that helps read a string line-by-line while
Browse files Browse the repository at this point in the history
maintaing the start/end index positions and the current line number
  • Loading branch information
sangupta committed Dec 19, 2014
1 parent 1e76ca9 commit cdbced7
Show file tree
Hide file tree
Showing 3 changed files with 388 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ target/*
.settings/*
/target
com/sangupta/jerry/*
/target/
178 changes: 178 additions & 0 deletions src/main/java/com/sangupta/jerry/io/StringLineIterator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
*
* jerry - Common Java Functionality
* Copyright (c) 2012-2014, Sandeep Gupta
*
* http://sangupta.com/projects/jerry
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.sangupta.jerry.io;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
* A simple iterator that reads a {@link String} line-by-line and
* also maintains the line number, the starting and ending index positions
* of the current read line.
*
* This may be useful when parsing a source file where positions need
* to be maintained.
*
* @author sangupta
*
*/
public class StringLineIterator implements Iterator<String> {

/**
* The character array backing this iterator.
*/
private final char[] chars;

/**
* The length of the string
*/
private final int length;

/**
* Holds the current line number
*/
private int lineNumber = -1;

/**
* Holds the beginning of the current line
*/
private int lineBegin = -1;

/**
* Holds the ending of current line
*/
private int lineEnd = -1;

/**
* Current read position in array
*/
private int current;

/**
* Create a new instance of the {@link StringLineIterator}.
*
* @param input
*/
public StringLineIterator(String input) {
this.chars = input.toCharArray();
this.length = input.length();
}

@Override
public boolean hasNext() {
if(this.current >= this.length) {
return false;
}

return true;
}

@Override
public String next() {
if(!hasNext()) {
throw new NoSuchElementException("No more lines");
}

if(this.lineNumber < 0) {
this.lineNumber = 0;
}

for(int index = this.current; index < this.length; index++) {
char c = chars[index];
if(c == '\n') {
this.lineNumber++;
this.lineBegin = this.current;
this.lineEnd = index;
this.current = index + 1;

return new String(Arrays.copyOfRange(this.chars, this.lineBegin, this.lineEnd));
}

if(c == '\r') {
this.lineNumber++;
this.lineBegin = this.current;
this.lineEnd = index;
this.current = index + 1;
if(chars[index + 1] == '\n') {
this.current++;
}

return new String(Arrays.copyOfRange(this.chars, this.lineBegin, this.lineEnd));
}
}

// we are till the end of file
this.lineNumber++;
this.lineBegin = this.current;
this.lineEnd = this.length;
this.current = this.length;
return new String(Arrays.copyOfRange(this.chars, this.lineBegin, this.length));
}

/**
* Return the current line number.
*
* @return
*/
public int getLineNumber() {
return this.lineNumber;
}

/**
* Return the index position at which the current line starts.
*
* @return
*/
public int getLineBegin() {
return this.lineBegin;
}

/**
* Return the index position at which the current line ends.
*
* @return
*/
public int getLineEnd() {
return this.lineEnd;
}

/**
* Return the index position at which the next read for the line will
* occur.
*
* @return
*/
public int getNextLineBegin() {
if(this.current >= this.length) {
return -1;
}

return this.current;
}

@Override
public void remove() {
throw new UnsupportedOperationException("Remove unsupported on LineIterator");
}

}
209 changes: 209 additions & 0 deletions src/test/java/com/sangupta/jerry/io/StringLineIteratorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/**
*
* jerry - Common Java Functionality
* Copyright (c) 2012-2014, Sandeep Gupta
*
* http://sangupta.com/projects/jerry
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package com.sangupta.jerry.io;

import junit.framework.Assert;

import org.junit.Test;

/**
* Unit tests for {@link StringLineIterator}.
*
* @author sangupta
*
*/
public class StringLineIteratorTest {

@Test
public void testNewLines() {
String input = "\n\n\n\n";
StringLineIterator it = new StringLineIterator(input);

Assert.assertEquals(-1, it.getLineNumber());
Assert.assertEquals(-1, it.getLineBegin());
Assert.assertEquals(-1, it.getLineEnd());

// first read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("", it.next());
Assert.assertEquals(1, it.getLineNumber());

Assert.assertTrue(it.hasNext());
Assert.assertEquals("", it.next());
Assert.assertEquals(2, it.getLineNumber());

Assert.assertTrue(it.hasNext());
Assert.assertEquals("", it.next());
Assert.assertEquals(3, it.getLineNumber());

Assert.assertTrue(it.hasNext());
Assert.assertEquals("", it.next());
Assert.assertEquals(4, it.getLineNumber());

Assert.assertFalse(it.hasNext());
}

@Test
public void testStringLineIterator1() {
String input = "one\ntwo\nthree\nfour";
StringLineIterator it = new StringLineIterator(input);

Assert.assertEquals(-1, it.getLineNumber());
Assert.assertEquals(-1, it.getLineBegin());
Assert.assertEquals(-1, it.getLineEnd());

// first read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("one", it.next());
Assert.assertEquals(1, it.getLineNumber());
Assert.assertEquals("one", input.substring(it.getLineBegin(), it.getLineEnd()));

// second read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("two", it.next());
Assert.assertEquals(2, it.getLineNumber());
Assert.assertEquals("two", input.substring(it.getLineBegin(), it.getLineEnd()));

// third read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("three", it.next());
Assert.assertEquals(3, it.getLineNumber());
Assert.assertEquals("three", input.substring(it.getLineBegin(), it.getLineEnd()));

// fourth read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("four", it.next());
Assert.assertEquals(4, it.getLineNumber());
Assert.assertEquals("four", input.substring(it.getLineBegin(), it.getLineEnd()));

Assert.assertFalse(it.hasNext());
}

@Test
public void testStringLineIterator2() {
String input = "one\rtwo\rthree\rfour";
StringLineIterator it = new StringLineIterator(input);

Assert.assertEquals(-1, it.getLineNumber());
Assert.assertEquals(-1, it.getLineBegin());
Assert.assertEquals(-1, it.getLineEnd());

// first read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("one", it.next());
Assert.assertEquals(1, it.getLineNumber());
Assert.assertEquals("one", input.substring(it.getLineBegin(), it.getLineEnd()));

// second read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("two", it.next());
Assert.assertEquals(2, it.getLineNumber());
Assert.assertEquals("two", input.substring(it.getLineBegin(), it.getLineEnd()));

// third read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("three", it.next());
Assert.assertEquals(3, it.getLineNumber());
Assert.assertEquals("three", input.substring(it.getLineBegin(), it.getLineEnd()));

// fourth read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("four", it.next());
Assert.assertEquals(4, it.getLineNumber());
Assert.assertEquals("four", input.substring(it.getLineBegin(), it.getLineEnd()));

Assert.assertFalse(it.hasNext());
}

@Test
public void testStringLineIterator3() {
String input = "one\r\ntwo\r\nthree\r\nfour";
StringLineIterator it = new StringLineIterator(input);

Assert.assertEquals(-1, it.getLineNumber());
Assert.assertEquals(-1, it.getLineBegin());
Assert.assertEquals(-1, it.getLineEnd());

// first read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("one", it.next());
Assert.assertEquals(1, it.getLineNumber());
Assert.assertEquals("one", input.substring(it.getLineBegin(), it.getLineEnd()));

// second read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("two", it.next());
Assert.assertEquals(2, it.getLineNumber());
Assert.assertEquals("two", input.substring(it.getLineBegin(), it.getLineEnd()));

// third read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("three", it.next());
Assert.assertEquals(3, it.getLineNumber());
Assert.assertEquals("three", input.substring(it.getLineBegin(), it.getLineEnd()));

// fourth read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("four", it.next());
Assert.assertEquals(4, it.getLineNumber());
Assert.assertEquals("four", input.substring(it.getLineBegin(), it.getLineEnd()));

Assert.assertFalse(it.hasNext());
}

@Test
public void testStringLineIterator4() {
String input = "one\r\ntwo\nthree\r\nfour";
StringLineIterator it = new StringLineIterator(input);

Assert.assertEquals(-1, it.getLineNumber());
Assert.assertEquals(-1, it.getLineBegin());
Assert.assertEquals(-1, it.getLineEnd());

// first read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("one", it.next());
Assert.assertEquals(1, it.getLineNumber());
Assert.assertEquals("one", input.substring(it.getLineBegin(), it.getLineEnd()));

// second read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("two", it.next());
Assert.assertEquals(2, it.getLineNumber());
Assert.assertEquals("two", input.substring(it.getLineBegin(), it.getLineEnd()));

// third read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("three", it.next());
Assert.assertEquals(3, it.getLineNumber());
Assert.assertEquals("three", input.substring(it.getLineBegin(), it.getLineEnd()));

// fourth read
Assert.assertTrue(it.hasNext());
Assert.assertEquals("four", it.next());
Assert.assertEquals(4, it.getLineNumber());
Assert.assertEquals("four", input.substring(it.getLineBegin(), it.getLineEnd()));

Assert.assertFalse(it.hasNext());
}

}

0 comments on commit cdbced7

Please sign in to comment.