All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.conqat.lib.commons.string.LineRangeStringParser Maven / Gradle / Ivy

There is a newer version: 2024.7.2
Show newest version
package org.conqat.lib.commons.string;

import java.util.ArrayList;
import java.util.List;

import org.conqat.lib.commons.assertion.CCSMAssert;
import org.conqat.lib.commons.collections.CompactLines;

/**
 * Parses a list of line numbers in the format like 1,3-5,8-10.
 *
 * We do the parsing in here manually as using StringTokenizer and {@link String#split(String)} is
 * around 10-20x slower and produces a lot of pressure on the garbage collector.
 */
public class LineRangeStringParser {

	/** The current (partial) line number. */
	private int currentLine = 0;

	/** The already parsed start line of a range while the end line is parsed. */
	private int startLine = 0;

	/**
	 * Whether the {@link #currentLine} refers to the start or end line number of a range.
	 */
	private boolean isParsingEndLine = false;

	/**
	 * Parses a list of line numbers in the format like 1,3-5,8-10.
	 *
	 * @return A collection of integers, which are described by the given string
	 */
	public CompactLines parse(String lineNumbersString) {
		reset();
		CompactLines lineNumbers = new CompactLines();
		for (int characterIndex = 0; characterIndex < lineNumbersString.length(); characterIndex++) {
			char currentChar = lineNumbersString.charAt(characterIndex);
			if (Character.isDigit(currentChar)) {
				currentLine = currentLine * 10 + Character.digit(currentChar, 10);
			} else if (currentChar == '-') {
				if (isParsingEndLine) {
					CCSMAssert.fail("Line number pattern at character " + characterIndex + " is invalid in: "
							+ lineNumbersString);
				}
				startLine = currentLine;
				currentLine = 0;
				isParsingEndLine = true;
			} else if (currentChar == ',') {
				appendLines(lineNumbers);
				reset();
			} else if (!Character.isWhitespace(currentChar)) {
				CCSMAssert.fail("Unexpected character " + currentChar + " in " + lineNumbersString);
			}
		}
		appendLines(lineNumbers);
		return lineNumbers;
	}

	/**
	 * Creates a list of {@link LineRange}s from a sorted and distinct plain list of line numbers.
	 */
	public static List compactifyToRanges(CompactLines lines) {
		if (lines.isEmpty()) {
			return new ArrayList<>();
		}

		int firstLine = lines.iterator().next();
		LineRange currentRange = new LineRange(firstLine, firstLine);

		List compactifiedRanges = new ArrayList<>();
		compactifiedRanges.add(currentRange);

		for (int currentLine : lines) {
			if (currentRange.getEnd() == currentLine || currentRange.getEnd() == currentLine - 1) {
				currentRange.setEnd(currentLine);
			} else {
				currentRange = new LineRange(currentLine, currentLine);
				compactifiedRanges.add(currentRange);
			}
		}
		return compactifiedRanges;
	}

	/** Parses the currently parsed line or line range to the lineNumbers. */
	private void appendLines(CompactLines lineNumbers) {
		if (currentLine == 0) {
			return;
		}
		if (isParsingEndLine) {
			lineNumbers.addRange(startLine, currentLine);
		} else {
			lineNumbers.add(currentLine);
		}
	}

	/** Resets all internal parsing state. */
	private void reset() {
		currentLine = 0;
		startLine = 0;
		isParsingEndLine = false;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy