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

com.github.leeonky.interpreter.StringWithPosition Maven / Gradle / Ivy

package com.github.leeonky.interpreter;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class StringWithPosition {
    private final String content;
    private final Set positions = new LinkedHashSet<>();
    private final Set rows = new LinkedHashSet<>();
    private final Set columns = new LinkedHashSet<>();

    public StringWithPosition(String content) {
        this.content = content;
    }

    public StringWithPosition position(int position) {
        if (position >= 0 && position <= content.length())
            positions.add(position);
        return this;
    }

    public StringWithPosition row(int position) {
        if (position >= 0 && position <= content.length())
            rows.add(position);
        return this;
    }

    public StringWithPosition column(int position) {
        if (position >= 0 && position <= content.length())
            columns.add(position);
        return this;
    }

    public String result() {
        return result(0);
    }

    public String result(int offset) {
        return result(content.substring(offset), offset);
    }

    private String result(String content, int offset) {
        try {
            StringBuilder result = new StringBuilder();
            SeparatedString separatedString = new SeparatedString(content, 0, offset, content);
            while (separatedString.printLine(result).hasNextLine())
                separatedString = separatedString.separatedNext().newLine(result);
            return result.toString();
        } catch (Exception e) {
            e.printStackTrace(System.err);
            return content;
        }
    }

    public String result(String prefix) {
        return result(prefix + content, -prefix.length());
    }

    public class SeparatedString {
        private final int startPosition;
        private final int offset;
        private final String content;
        private final String newLine;
        private final String[] lines;

        public SeparatedString(String leftContent, int startPosition, int offset, String content) {
            lines = leftContent.split("\r\n|\n\r|\n|\r", 2);
            newLine = fetchNewLine(leftContent);
            this.startPosition = startPosition;
            this.offset = offset;
            this.content = content;
        }

        private String fetchNewLine(String content) {
            return hasNextLine() ? content.substring(lines[0].length(), content.length() - lines[1].length()) : "\n";
        }

        public boolean hasNextLine() {
            return lines.length == 2;
        }

        private SeparatedString printLine(StringBuilder builder) {
            builder.append(lines[0]);
            printPositions(builder, positions);
            printPositions(builder, columns);
            printWholeLine(builder);
            return this;
        }

        private void printWholeLine(StringBuilder builder) {
            List linePositions = linePosition(rows);
            if (!linePositions.isEmpty()) {
                builder.append(newLine);
                for (int i = lengthWithFullWidthChar(lines[0]); i > -1; i--)
                    builder.append('^');
            }
        }

        private int lengthWithFullWidthChar(String line) {
            return line.length() + (int) line.chars().filter(this::isFullWidth).count();
        }

        private void printPositions(StringBuilder builder, Collection positions) {
            List linePositions = linePosition(positions);
            if (!linePositions.isEmpty()) {
                int lastPosition = startPosition;
                builder.append(newLine);
                for (int eachPosition : linePositions) {
                    builder.append(NotationMark(lengthWithFullWidthChar(content.substring(lastPosition, eachPosition))));
                    if (eachPosition < content.length() && isFullWidth(content.charAt(eachPosition)))
                        builder.append(' ');
                    lastPosition = eachPosition + newLine.length();
                }
                if (builder.charAt(builder.length() - 1) == ' ')
                    builder.deleteCharAt(builder.length() - 1);
            }
        }

        private String NotationMark(int count) {
            return String.format("%" + (count + 1) + "c", '^');
        }

        private List linePosition(Collection positions) {
            return positions.stream().map(i -> i - offset)
                    .filter(i -> i >= startPosition && i <= startPosition + lines[0].length())
                    .sorted().collect(Collectors.toList());
        }

        private SeparatedString separatedNext() {
            return new SeparatedString(lines[1], startPosition + lines[0].length() + newLine.length(), offset, content);
        }

        private SeparatedString newLine(StringBuilder result) {
            result.append(newLine);
            return this;
        }

        private boolean isFullWidth(int c) {
            return !('\u0000' <= c && c <= '\u00FF' || '\uFF61' <= c && c <= '\uFFDC' || '\uFFE8' <= c && c <= '\uFFEE');
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy