package com.github.rwitzel.streamflyer.support; import static org.junit.Assert.assertEquals; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; import org.junit.Test; import com.github.rwitzel.streamflyer.core.AfterModification; import com.github.rwitzel.streamflyer.core.Modifier; import com.github.rwitzel.streamflyer.core.ModifyingReader; import com.github.rwitzel.streamflyer.regex.MatchProcessor; import com.github.rwitzel.streamflyer.regex.MatchProcessorResult; import com.github.rwitzel.streamflyer.regex.OnStreamMatcher; import com.github.rwitzel.streamflyer.regex.RegexModifier; import com.github.rwitzel.streamflyer.regex.addons.util.DoNothingProcessor; import com.github.rwitzel.streamflyer.util.ModificationFactory; import com.github.rwitzel.streamflyer.util.statistics.LineColumnAwareModificationFactory; /** * <a href="https://groups.google.com/forum/#!topic/streamflyer-discuss/tfoOlLFqLLc">Tracking the line and column * number</a> * * @author rwoo */ public class LineColumnOnRegexMatchTest { private LineColumnAwareModificationFactory fac; private int firstCharIndex; public class PositionAwareRegexModifier extends RegexModifier { public PositionAwareRegexModifier(String regex, int flags, MatchProcessor matchProcessor, int minimumLengthOfLookBehind, int newNumberOfChars) { super(regex, flags, matchProcessor, minimumLengthOfLookBehind, newNumberOfChars); } @Override public AfterModification modify(StringBuilder characterBuffer, int firstModifiableCharacterInBuffer, boolean endOfStreamHit) { firstCharIndex = firstModifiableCharacterInBuffer; return super.modify(characterBuffer, firstModifiableCharacterInBuffer, endOfStreamHit); } @Override protected void init(OnStreamMatcher matcher, MatchProcessor matchProcessor, int minimumLengthOfLookBehind, int newNumberOfChars) { super.init(matcher, matchProcessor, minimumLengthOfLookBehind, newNumberOfChars); ModificationFactory delegate = new ModificationFactory(minimumLengthOfLookBehind, newNumberOfChars); this.factory = new LineColumnAwareModificationFactory(delegate); this.matchProcessor = matchProcessor; this.matcher = matcher; this.newNumberOfChars = newNumberOfChars; fac = (LineColumnAwareModificationFactory) this.factory; } } public class PositionSavingMatchProcessor extends DoNothingProcessor { private List<String> matchPositions = new ArrayList<String>(); @Override public MatchProcessorResult process(StringBuilder characterBuffer, int firstModifiableCharacterInBuffer, MatchResult matchResult) { long unmatchedStartLine = fac.getCurrentLine(); long unmatchedStartColumn = fac.getCurrentColumn(); int unmatchedStart = firstCharIndex; int unmatchedEnd = matchResult.start(); String unmatched = characterBuffer.substring(unmatchedStart, unmatchedEnd); String matchPosition = matchPosition(unmatchedStartLine, unmatchedStartColumn, unmatched); matchPositions.add(matchPosition); return super.process(characterBuffer, firstModifiableCharacterInBuffer, matchResult); } private String matchPosition(long unmatchedStartLine, long unmatchedStartColumn, String unmatched) { Matcher matcher = Pattern.compile("\r\n|\r|\n").matcher(unmatched); int numLines = 0; int endOfLastLineBreak = 0; while (matcher.find()) { numLines++; endOfLastLineBreak = matcher.end(); } long lineNumber = unmatchedStartLine + numLines; long columnNumber; if (numLines == 0) { columnNumber = unmatchedStartColumn + unmatched.length(); } else { columnNumber = unmatched.length() - endOfLastLineBreak; // length of last line in 'unmatched' } return "line: " + lineNumber + ", column: " + columnNumber; } public List<String> getMatchPositions() { return matchPositions; } } @Test public void testFoundLineAndColumn() throws Exception { PositionSavingMatchProcessor processor = new PositionSavingMatchProcessor(); Modifier modifier = new PositionAwareRegexModifier("STREAMFLYER", 0, processor, 1, 500); String input = IOUtils.toString(getClass().getResourceAsStream("LineColumnOnRegexMatchTest.txt"), "UTF-8"); Reader reader = new ModifyingReader(new StringReader(input), modifier); IOUtils.toString(reader); reader.close(); List<String> positions = processor.getMatchPositions(); assertEquals(4, positions.size()); assertEquals("line: 162, column: 6", positions.get(0)); assertEquals("line: 162, column: 24", positions.get(1)); assertEquals("line: 781, column: 6", positions.get(2)); assertEquals("line: 781, column: 24", positions.get(3)); } @Test public void testFoundLineAndColumn2() throws Exception { PositionSavingMatchProcessor processor = new PositionSavingMatchProcessor(); Modifier modifier = new PositionAwareRegexModifier("\\Qfile \\E(.*)\\Q.\\E", 0, processor, 1, 500); String input = IOUtils.toString(getClass().getResourceAsStream("LineColumnOnRegexMatchTest2.txt"), "UTF-8"); Reader reader = new ModifyingReader(new StringReader(input), modifier); IOUtils.toString(reader); reader.close(); List<String> positions = processor.getMatchPositions(); assertEquals(4, positions.size()); assertEquals("line: 0, column: 5", positions.get(0)); assertEquals("line: 1, column: 8", positions.get(1)); assertEquals("line: 2, column: 5", positions.get(2)); assertEquals("line: 3, column: 0", positions.get(3)); } }