summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/ioutils/blocks/SimpleBlockReader.java
blob: ac77f974b1ae97454bd532aa78ecbcbea3a25bc1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package bjc.utils.ioutils.blocks;

import java.io.IOException;
import java.io.Reader;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.regex.Pattern;

import bjc.utils.funcutils.StringUtils;

/**
 * Simple implementation of {@link BlockReader}.
 *
 * NOTE: The EOF marker is always treated as a delimiter. You are expected to
 * handle blocks that may be shorter than you expect.
 *
 * @author EVE
 *
 */
public class SimpleBlockReader implements BlockReader {
	/*
	 * I/O source for blocks.
	 */
	private final Scanner blockReader;

	/*
	 * The current block.
	 */
	private Block currBlock;

	/*
	 * Info about the current block.
	 */
	private int blockNo;
	private int lineNo;

	/**
	 * Create a new block reader.
	 *
	 * @param blockDelim
	 *        The pattern that separates blocks. Note that the end of file
	 *        is always considered to end a block.
	 *
	 * @param source
	 *        The source to read blocks from.
	 */
	public SimpleBlockReader(final String blockDelim, final Reader source) {
		blockReader = new Scanner(source);

		final String pattern = String.format("(?:%s)|\\Z", blockDelim);
		final Pattern pt = Pattern.compile(pattern, Pattern.MULTILINE);

		blockReader.useDelimiter(pt);

		lineNo = 1;
	}

	/**
	 * Create a new block reader.
	 *
	 * @param blockDelim
	 *        The pattern that separates blocks. Note that the end of file
	 *        is always considered to end a block.
	 *
	 * @param source
	 *        The source to read blocks from.
	 *        NOTE: This does modify the provided scanner.
	 */
	public SimpleBlockReader(final String blockDelim, final Scanner source) {
		blockReader = source;

		final String pattern = String.format("(?:%s)|\\Z", blockDelim);
		final Pattern pt = Pattern.compile(pattern, Pattern.MULTILINE);

		blockReader.useDelimiter(pt);

		lineNo = 1;
	}

	@Override
	public boolean hasNextBlock() {
		return blockReader.hasNext();
	}

	@Override
	public Block getBlock() {
		return currBlock;
	}

	@Override
	public boolean nextBlock() {
		try {
			/*
			 * Read in a new block, and keep the line numbers sane.
			 */
			final String blockContents = blockReader.next();

			final int blockStartLine = lineNo;
			final int blockEndLine = lineNo + StringUtils.countMatches(blockContents, "\\R");

			lineNo = blockEndLine;
			blockNo += 1;

			currBlock = new Block(blockNo, blockContents, blockStartLine, blockEndLine);

			return true;
		} catch(final NoSuchElementException nseex) {
			// Don't null out the current block, let it be the last
			// one
			//currBlock = null;

			return false;
		}
	}

	@Override
	public int getBlockCount() {
		return blockNo;
	}

	@Override
	public void close() throws IOException {
		blockReader.close();
	}

	/**
	 * Set the delimiter used to separate blocks.
	 *
	 * @param delim
	 *        The delimiter used to separate blocks.
	 */
	public void setDelimiter(final String delim) {
		blockReader.useDelimiter(delim);
	}

	@Override
	public String toString() {
		return String.format("SimpleBlockReader [currBlock=%s, blockNo=%s]", currBlock, blockNo);
	}
}