Java tutorial
/* * Copyright 2016 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.googlejavaformat; import com.google.common.base.CharMatcher; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterators; import java.util.Iterator; import java.util.NoSuchElementException; /** Platform-independent newline handling. */ public class Newlines { /** Returns the number of line breaks in the input. */ public static int count(String input) { return Iterators.size(lineOffsetIterator(input)) - 1; } /** Returns the index of the first break in the input, or {@code -1}. */ public static int firstBreak(String input) { Iterator<Integer> it = lineOffsetIterator(input); it.next(); return it.hasNext() ? it.next() : -1; } private static final ImmutableSet<String> BREAKS = ImmutableSet.of("\r\n", "\n", "\r"); /** Returns true if the entire input string is a recognized line break. */ public static boolean isNewline(String input) { return BREAKS.contains(input); } /** Returns the length of the newline sequence at the current offset, or {@code -1}. */ public static int hasNewlineAt(String input, int idx) { for (String b : BREAKS) { if (input.startsWith(b, idx)) { return b.length(); } } return -1; } /** * Returns the terminating line break in the input, or {@code null} if the input does not end in a * break. */ public static String getLineEnding(String input) { for (String b : BREAKS) { if (input.endsWith(b)) { return b; } } return null; } /** * Returns the first line separator in the text, or {@code "\n"} if the text does not contain a * single line separator. */ public static String guessLineSeparator(String text) { for (int i = 0; i < text.length(); i++) { char c = text.charAt(i); switch (c) { case '\r': if (i + 1 < text.length() && text.charAt(i + 1) == '\n') { return "\r\n"; } return "\r"; case '\n': return "\n"; default: break; } } return "\n"; } /** Returns true if the input contains any line breaks. */ public static boolean containsBreaks(String text) { return CharMatcher.anyOf("\n\r").matchesAnyOf(text); } /** Returns an iterator over the start offsets of lines in the input. */ public static Iterator<Integer> lineOffsetIterator(String input) { return new LineOffsetIterator(input); } /** Returns an iterator over lines in the input, including trailing whitespace. */ public static Iterator<String> lineIterator(String input) { return new LineIterator(input); } private static class LineOffsetIterator implements Iterator<Integer> { private int curr = 0; private int idx = 0; private final String input; private LineOffsetIterator(String input) { this.input = input; } @Override public boolean hasNext() { return curr != -1; } @Override public Integer next() { if (curr == -1) { throw new NoSuchElementException(); } int result = curr; advance(); return result; } private void advance() { for (; idx < input.length(); idx++) { char c = input.charAt(idx); switch (c) { case '\r': if (idx + 1 < input.length() && input.charAt(idx + 1) == '\n') { idx++; } // falls through case '\n': idx++; curr = idx; return; default: break; } } curr = -1; } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } private static class LineIterator implements Iterator<String> { int idx; String curr; private final String input; private final Iterator<Integer> indices; private LineIterator(String input) { this.input = input; this.indices = lineOffsetIterator(input); idx = indices.next(); // read leading 0 } private void advance() { int last = idx; if (indices.hasNext()) { idx = indices.next(); } else if (hasNext()) { // no terminal line break idx = input.length(); } else { throw new NoSuchElementException(); } curr = input.substring(last, idx); } @Override public boolean hasNext() { return idx < input.length(); } @Override public String next() { advance(); return curr; } @Override public void remove() { throw new UnsupportedOperationException("remove"); } } }