mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8200434
: String::align, String::indent
Reviewed-by: abuckley, smarks, sherman, rriggs, jrose, sundar, igerasim, briangoetz, darcy, jjg
This commit is contained in:
parent
2065ebd890
commit
12dad310bb
4 changed files with 541 additions and 34 deletions
|
@ -40,12 +40,15 @@ import java.util.StringJoiner;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
/**
|
||||
* The {@code String} class represents character strings. All
|
||||
* string literals in Java programs, such as {@code "abc"}, are
|
||||
|
@ -2755,12 +2758,9 @@ public final class String
|
|||
return indexOfNonWhitespace() == length();
|
||||
}
|
||||
|
||||
private int indexOfNonWhitespace() {
|
||||
if (isLatin1()) {
|
||||
return StringLatin1.indexOfNonWhitespace(value);
|
||||
} else {
|
||||
return StringUTF16.indexOfNonWhitespace(value);
|
||||
}
|
||||
private Stream<String> lines(int maxLeading, int maxTrailing) {
|
||||
return isLatin1() ? StringLatin1.lines(value, maxLeading, maxTrailing)
|
||||
: StringUTF16.lines(value, maxLeading, maxTrailing);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2794,8 +2794,181 @@ public final class String
|
|||
* @since 11
|
||||
*/
|
||||
public Stream<String> lines() {
|
||||
return isLatin1() ? StringLatin1.lines(value)
|
||||
: StringUTF16.lines(value);
|
||||
return lines(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the indentation of each line of this string based on the value of
|
||||
* {@code n}, and normalizes line termination characters.
|
||||
* <p>
|
||||
* This string is conceptually separated into lines using
|
||||
* {@link String#lines()}. Each line is then adjusted as described below
|
||||
* and then suffixed with a line feed {@code "\n"} (U+000A). The resulting
|
||||
* lines are then concatenated and returned.
|
||||
* <p>
|
||||
* If {@code n > 0} then {@code n} spaces (U+0020) are inserted at the
|
||||
* beginning of each line. {@link String#isBlank() Blank lines} are
|
||||
* unaffected.
|
||||
* <p>
|
||||
* If {@code n < 0} then up to {@code n}
|
||||
* {@link Character#isWhitespace(int) white space characters} are removed
|
||||
* from the beginning of each line. If a given line does not contain
|
||||
* sufficient white space then all leading
|
||||
* {@link Character#isWhitespace(int) white space characters} are removed.
|
||||
* Each white space character is treated as a single character. In
|
||||
* particular, the tab character {@code "\t"} (U+0009) is considered a
|
||||
* single character; it is not expanded.
|
||||
* <p>
|
||||
* If {@code n == 0} then the line remains unchanged. However, line
|
||||
* terminators are still normalized.
|
||||
* <p>
|
||||
*
|
||||
* @param n number of leading
|
||||
* {@link Character#isWhitespace(int) white space characters}
|
||||
* to add or remove
|
||||
*
|
||||
* @return string with indentation adjusted and line endings normalized
|
||||
*
|
||||
* @see String#lines()
|
||||
* @see String#isBlank()
|
||||
* @see Character#isWhitespace(int)
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public String indent(int n) {
|
||||
return isEmpty() ? "" : indent(n, false);
|
||||
}
|
||||
|
||||
private String indent(int n, boolean removeBlanks) {
|
||||
Stream<String> stream = removeBlanks ? lines(Integer.MAX_VALUE, Integer.MAX_VALUE)
|
||||
: lines();
|
||||
if (n > 0) {
|
||||
final String spaces = " ".repeat(n);
|
||||
stream = stream.map(s -> s.isBlank() ? s : spaces + s);
|
||||
} else if (n == Integer.MIN_VALUE) {
|
||||
stream = stream.map(s -> s.stripLeading());
|
||||
} else if (n < 0) {
|
||||
stream = stream.map(s -> s.substring(Math.min(-n, s.indexOfNonWhitespace())));
|
||||
}
|
||||
return stream.collect(Collectors.joining("\n", "", "\n"));
|
||||
}
|
||||
|
||||
private int indexOfNonWhitespace() {
|
||||
return isLatin1() ? StringLatin1.indexOfNonWhitespace(value)
|
||||
: StringUTF16.indexOfNonWhitespace(value);
|
||||
}
|
||||
|
||||
private int lastIndexOfNonWhitespace() {
|
||||
return isLatin1() ? StringLatin1.lastIndexOfNonWhitespace(value)
|
||||
: StringUTF16.lastIndexOfNonWhitespace(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes vertical and horizontal white space margins from around the
|
||||
* essential body of a multi-line string, while preserving relative
|
||||
* indentation.
|
||||
* <p>
|
||||
* This string is first conceptually separated into lines as if by
|
||||
* {@link String#lines()}.
|
||||
* <p>
|
||||
* Then, the <i>minimum indentation</i> (min) is determined as follows. For
|
||||
* each non-blank line (as defined by {@link String#isBlank()}), the
|
||||
* leading {@link Character#isWhitespace(int) white space} characters are
|
||||
* counted. The <i>min</i> value is the smallest of these counts.
|
||||
* <p>
|
||||
* For each non-blank line, <i>min</i> leading white space characters are
|
||||
* removed. Each white space character is treated as a single character. In
|
||||
* particular, the tab character {@code "\t"} (U+0009) is considered a
|
||||
* single character; it is not expanded.
|
||||
* <p>
|
||||
* Leading and trailing blank lines, if any, are removed. Trailing spaces are
|
||||
* preserved.
|
||||
* <p>
|
||||
* Each line is suffixed with a line feed character {@code "\n"} (U+000A).
|
||||
* <p>
|
||||
* Finally, the lines are concatenated into a single string and returned.
|
||||
*
|
||||
* @apiNote
|
||||
* This method's primary purpose is to shift a block of lines as far as
|
||||
* possible to the left, while preserving relative indentation. Lines
|
||||
* that were indented the least will thus have no leading white space.
|
||||
*
|
||||
* Example:
|
||||
* <blockquote><pre>
|
||||
* `
|
||||
* This is the first line
|
||||
* This is the second line
|
||||
* `.align();
|
||||
*
|
||||
* returns
|
||||
* This is the first line
|
||||
* This is the second line
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @return string with margins removed and line terminators normalized
|
||||
*
|
||||
* @see String#lines()
|
||||
* @see String#isBlank()
|
||||
* @see String#indent(int)
|
||||
* @see Character#isWhitespace(int)
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public String align() {
|
||||
return align(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes vertical and horizontal white space margins from around the
|
||||
* essential body of a multi-line string, while preserving relative
|
||||
* indentation and with optional indentation adjustment.
|
||||
* <p>
|
||||
* Invoking this method is equivalent to:
|
||||
* <blockquote>
|
||||
* {@code this.align().indent(n)}
|
||||
* </blockquote>
|
||||
*
|
||||
* @apiNote
|
||||
* Examples:
|
||||
* <blockquote><pre>
|
||||
* `
|
||||
* This is the first line
|
||||
* This is the second line
|
||||
* `.align(0);
|
||||
*
|
||||
* returns
|
||||
* This is the first line
|
||||
* This is the second line
|
||||
*
|
||||
*
|
||||
* `
|
||||
* This is the first line
|
||||
* This is the second line
|
||||
* `.align(4);
|
||||
* returns
|
||||
* This is the first line
|
||||
* This is the second line
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param n number of leading white space characters
|
||||
* to add or remove
|
||||
*
|
||||
* @return string with margins removed, indentation adjusted and
|
||||
* line terminators normalized
|
||||
*
|
||||
* @see String#align()
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public String align(int n) {
|
||||
if (isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
int outdent = lines().filter(not(String::isBlank))
|
||||
.mapToInt(String::indexOfNonWhitespace)
|
||||
.min()
|
||||
.orElse(0);
|
||||
return indent(n - outdent, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue