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

javax0.jamal.tools.Range Maven / Gradle / Ivy

There is a newer version: 2.8.1
Show newest version
package javax0.jamal.tools;

import javax0.jamal.api.BadSyntax;

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

/**
 * A range is a pair of negative, or positive integers, representing the start and the end of a range.
 * It is primarily used to denote line ranges.
 */
public class Range {

    public static class Lines {
        public static void filter(final StringBuilder sb, final String rangesSpecification) throws BadSyntax {
            final var lines = sb.toString().split("\n", -1);
            for (int i = 0; i < lines.length - 1; i++) {
                lines[i] = lines[i] + "\n";
            }
            final var ranges = Range.calculateFrom(rangesSpecification, lines.length);
            sb.setLength(0);
            boolean nlMissing = false;
            for (final var range : ranges) {
                final int step = range.to >= range.from ? 1 : -1;
                if (nlMissing) {
                    sb.append("\n");
                }
                for (int i = range.from; i != range.to + step; i += step) {
                    if (i <= lines.length && i > 0) {
                        final var line = lines[i - 1];
                        sb.append(line);
                        nlMissing = line.length() == 0 || line.charAt(line.length() - 1) != '\n';
                    }
                }
            }
        }
    }

    final public int from;
    final public int to;

    private Range(final int from, final int to) {
        this.from = from;
        this.to = to;
    }

    public static Range range(final int from, final int to) {
        return new Range(from, to);
    }

    /**
     * Calculate the list of the ranges given as a textual list in the string {@code s}.
     * 

* The string can contain one or more ange definitions. * Range definitions are separated by commas {@code ,} or by semicolon {@code ;} or these mixed. * Ranges can overlap, repeated, and can have direction starting with a value greater than the end value. *

* A range definition can be a pure number {@code N}, which is the same as {@code N..N}, or a range definition in * the format {@code START .. END}. Here {@code START} is the first value in the range and {@code END} is the last. *

* The {@code START} and {@code END} can be positive or negative, but it cannot be zero. *

* Negative values are corrected counting from the end of the range. * If a range {@code START} and/or {@code END} value is larger than {@code n} or smaller than {@code -n} then the * range will contain the value, which is out of the allowed values. *

* It is up to the caller to interpret negative (after correction) and larger than {@code n} values. * It is also the caller responsibility to use the end values exclusive or inclusive. * Usually the start value is inclusive and the end value is exclusive in Java, like in {@code substring()}. *

* On the other hand, the caller may not use ths values as zero based, because zero is not an allowed value. * This is because these ranges are used to specify lines and in the different editors the line numbering starts * with one. * * @param s the string with the list of the ranges * @param n the maximum number that can be in the range. When a number in a range is negative then it is calculated * from this number backwards (like in Python, when you specify an array split as {@code a[5:-2]}). * @return a list of ranges with line numbers in it. * @throws BadSyntax if the formatting of the string is incorrect or a value is zero. */ public static List calculateFrom(final String s, final int n) throws BadSyntax { final var rangeSpecs = s.split("[,;]"); final var ranges = new ArrayList(); for (final var range : rangeSpecs) { var startStop = range.split("\\.\\."); if (startStop.length == 1) { startStop = new String[]{range, range}; } BadSyntax.when(startStop.length != 2, "The line range %s is not valid", range); final int to, from; try { from = str2int(startStop[0]); to = str2int(startStop[1]); } catch (NumberFormatException nfe) { throw new BadSyntax("The line range " + range + " is not valid"); } BadSyntax.when(from == 0 || to == 0 || from == -n || to == -n, "The line range %s is not valid", range); ranges.add(range(correct(from, n), correct(to, n))); } return ranges; } private static int str2int(final String s) { final var t = s.trim(); if (t.equalsIgnoreCase("inf") || t.equalsIgnoreCase("infinity")) { return Integer.MAX_VALUE; } return Integer.parseInt(t); } private static int correct(final int from, final int n) { if (from < 0) { return from + n; } else { return from; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy