package Java; import static Java.Characters.isJavaOrUnicodeWhitespace; import static java.lang.Character.charCount; /** Indicant of precisely where in a line of text a particular character occurs. */ public class IntralineCharacterPointer { /** @see #line * @see #column */ public IntralineCharacterPointer( String line, int column ) { this.line = line; this.column = column; } /** The columnar offset at which the character occurs. Columnar offsets are zero based and measured * in terms of grapheme clusters, beginning with the first cluster at offset zero in the text line. * * @see * Grapheme cluster boundaries in Unicode text segmentation */ public final int column; /** A copy of the text line in which the character occurs, with or without any terminal newline. */ public final String line; /** Returns a multi-line string comprising an echo of the text line together with a column marker. */ public final String markedLine() { return markedLine( line, column ); } /** Returns a multi-line string comprising an echo of a text line together with a column marker. * * @param line The text line to be marked, with or without any terminal newline. * @param column The columnar offset at which to mark the line. Columnar offsets are zero based * and measured in terms of grapheme clusters, beginning with the first cluster at offset zero * in the text line. * @see * Grapheme cluster boundaries in Unicode text segmentation */ public static String markedLine( final String line, final int column ) { final StringBuilder b = new StringBuilder(); for( int ch, c = 0, cN = line.length(); c < cN; c += charCount(ch) ) { // Sanitize: ch = line.codePointAt( c ); // By full code point, not to miss the problematic ones. b.appendCodePoint( isJavaOrUnicodeWhitespace(ch)? ' ' : ch ); } b.append( '\n' ); for( int c = column; c > 0; --c ) b.append( ' ' ); b.append( '^' ); return b.toString(); } /** Returns a multi-line string comprising an echo of a text line together with a column marker. * * @param line The text line to be marked, with or without any terminal newline. * @param c The zero-based offset of the character whose column to mark. */ public static String markedLine( final String line, final int c, final GraphemeClusterCounter gcc ) { return markedLine( line, /*column*/gcc.clusterCount(line,0,c) ); } /** Returns a multi-line string comprising an echo of a text line together with a column marker. * * @param head Part one of the text line to be marked. This might, for example, * be a sequence of space characters that serve to indent the text. * @param body Part two of the text line to be marked, with or without any terminal newline. * @param b The zero-based offset in `body` of the character whose column to mark. */ public static String markedLine( final String head, final String body, final int b, final GraphemeClusterCounter gcc ) { return markedLine( /*line*/head + body, /*c*/head.length() + b, gcc ); }} // Copyright © 2021-2022 Michael Allan. Licence MIT.