We’re going to try align.
Example:
String a = `
abc
def
ghi
`.align();
Result:
abc
def
ghi
Example:
String b = `
abc
def
ghi
`.align(4);
Result:
abc
def
ghi
Example:
String c = `
abc
def
ghi
`.align(-1);
Result:
abc
def
ghi
Implementation:
/**
* When applied to a string, left justifies
* lines without loss of relative indentation. This is
* accomplished by removing an equal number of
* {@link Character#isWhitespace(int) white space} characters
* from each line so that at least one line has a non-white
* space character in the left-most position.
* The result is realigned by indenting {@code n}
* {@link Character#isWhitespace(int) white space}
* characters.
* First and last blank lines introduced to allow
* bracketing delimiters to appear on separate source lines
* are also removed.
* <p>
* @apinote All
* {@link Character#isWhitespace(int) white space characters},
* including tab, are treated as a single space.
* <p>
* @apiNote The all line terminators in the result will be
* replaced with line feed {@code "\n"} ({@code U+000A}).
*
* @param n number of leading white space characters
* to adjust
*
* @return string left justified
*
* @see Character#isWhitespace(int)
* @see String#indent(int)
* @see String#lines()
* @see String#lines(LinesOptions... options)
*
* @since 11
*/
public String align(int n) {
if (isEmpty()) {
return "";
}
int min = lines().skip(1)
.filter(not(String::isEmpty))
.mapToInt(String::indexOfNonWhitespace)
.min()
.orElse(0);
return indent(n - min, true);
}
/**
* When applied to a string, left justifies
* lines without loss of relative indentation. This is
* accomplished by removing an equal number of
* {@link Character#isWhitespace(int) white space} characters
* from each line so that at least one line has a non-white
* space character in the left-most position.
* First and last blank lines introduced to allow
* bracketing delimiters to appear on separate source lines
* are also removed.
* <p>
* @apinote All
* {@link Character#isWhitespace(int) white space characters},
* including tab, are treated as a single space.
* <p>
* @apiNote The all line terminators in the result will be
* replaced with line feed {@code "\n"} ({@code U+000A}).
*
* @return string left justified
*
* @see Character#isWhitespace(int)
* @see String#indent(int)
* @see String#lines()
* @see String#lines(LinesOptions... options)
*
* @since 11
*/
public String align() {
return align(0);
}
With lines, we’re going to drop the LinesOptions silliness and just go with
maxLeading and maxTrailing.
Example:
int d = `
abc
def
ghi
`.lines().count();
Result:
5
Example:
int e = `
abc
def
ghi
`.lines(1, 1).count();
Result:
3
Example:
int f = `
abc
def
ghi
`.lines(Integer.Max_VALUE,Integer.Max_VALUE).count();
Result:
3
Implementation:
/**
* Returns a stream of substrings extracted from this string
* partitioned by line terminators.
* <p>
* Line terminators recognized are line feed
* {@code "\n"} ({@code U+000A}),
* carriage return
* {@code "\r"} ({@code U+000D})
* and a carriage return followed immediately by a line feed
* {@code "\r\n"} ({@code U+000D U+000A}).
* <p>
* The stream returned by this method contains each line of
* this string that is terminated by a line terminator except that
* the last line can either be terminated by a line terminator or the
* end of the string.
* The lines in the stream are in the order in which
* they occur in this string and do not include the line terminators
* partitioning the lines.
* <p>
* The {@code maxLeading} and {@code maxTrailing} arguments can be
* used to remove incidental blank lines from the beginning and
* end of a multi-line sequence. A value of {@code 1} will remove
* at most one blank line. A value of {@link Integer.MAX_VALUE}
* will all leading or trailing blank lines.
*
* @implNote This method provides better performance than
* split("\R") by supplying elements lazily and
* by faster search of new line terminators.
*
* @param maxLeading the maximum number of leading blank lines
* to remove
*
* @param maxTrailing the maximum number of trailing blank lines
* to remove
*
* @return the stream of strings extracted from this string
* partitioned by line terminators
*
* @throws IllegalArgumentException if {@code maxLeading} or
* {@code maxTrailing} is negative.
*
* @since 11
*/
public Stream<String> lines(int maxLeading, int maxTrailing) {
if (maxLeading < 0) {
throw new IllegalArgumentException("maxLeading is negative: " +
maxLeading);
}
if (maxTrailing < 0) {
throw new IllegalArgumentException("maxTrailing is negative: " +
maxTrailing);
}
Stream<String> stream = isLatin1() ? StringLatin1.lines(value, maxLeading,
maxTrailing)
: StringUTF16.lines(value, maxLeading,
maxTrailing);
return stream;
}
/**
* Returns a stream of substrings extracted from this string
* partitioned by line terminators.
* <p>
* Line terminators recognized are line feed
* {@code "\n"} ({@code U+000A}),
* carriage return
* {@code "\r"} ({@code U+000D})
* and a carriage return followed immediately by a line feed
* {@code "\r\n"} ({@code U+000D U+000A}).
* <p>
* The stream returned by this method contains each line of
* this string that is terminated by a line terminator except that
* the last line can either be terminated by a line terminator or the
* end of the string.
* The lines in the stream are in the order in which
* they occur in this string and do not include the line terminators
* partitioning the lines.
*
* @implNote This method provides better performance than
* split("\R") by supplying elements lazily and
* by faster search of new line terminators.
*
* @return the stream of strings extracted from this string
* partitioned by line terminators
*
* @since 11
*/
public Stream<String> lines() {
return lines(0, 0);
}
> On Jun 7, 2018, at 2:49 PM, Guy Steele <[email protected]> wrote:
>
>
>> On Jun 7, 2018, at 1:48 PM, Brian Goetz <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>>>
>>> Part of the goal was to shorten the name to reduce the annoyance quotient.
>>> “reindent” speaks to me more than “leftMargin” (starts searching
>>> thesaurus.) The combo makes sense too. Then you start thinking in terms of
>>> indent is just reindent without the magic.
>>
>> reindent() is OK by me; its a little longer but it says what it means, and
>> still less fussy than trimMargin() or autoMagicReindent().
>>
>> undent() is shorter, but sounds more like what happens at an auto-body
>> repair shop :)
>
> Or redent(), which happens a week later. :-)
>