blob: f0abe50fa8d753c94945eae7358000b142013e44 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.jcommons.util;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import org.eclipse.statet.jcommons.collections.ImCollection;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
@NonNullByDefault
public final class StringUtils {
private static final byte[] U_DIGITS= {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F',
};
/**
* Formats the Unicode code points in the standard U+XXXX notation.
*
* @param cp the code point
* @return a string with the formatted code point
*/
@SuppressWarnings("deprecation")
public static String formatCodePoint(int cp) {
final int nDigits= Math.max(((Integer.SIZE + 7 - Integer.numberOfLeadingZeros(cp)) / 8) * 2, 4);
final byte[] latin1= new byte[2 + nDigits];
latin1[0]= 'U';
latin1[1]= '+';
int i= latin1.length;
do {
latin1[--i]= U_DIGITS[cp & 0xF];
cp >>>= 4;
} while (i > 2);
return new String(latin1, 0, 0, latin1.length);
}
public static int firstIndexOfNonTrim(final String s, int start, final int end) {
if (start < 0 || end > s.length()) {
throw new StringIndexOutOfBoundsException();
}
while (start < end && s.charAt(start) <= ' ') {
start++;
}
return start;
}
public static int firstIndexOfNonTrim(final String s) {
int start= 0;
final int end= s.length();
while (start < end && s.charAt(start) <= ' ') {
start++;
}
return start;
}
public static int lastIndexOfNonTrim(final String s, final int start, int end) {
if (start < 0 || end > s.length()) {
throw new StringIndexOutOfBoundsException();
}
while (start < end && s.charAt(end - 1) <= ' ') {
end--;
}
return end;
}
public static int lastIndexOfNonTrim(final String s) {
int end= s.length();
while (0 < end && s.charAt(end - 1) <= ' ') {
end--;
}
return end;
}
public static String trim(final String s, int start, int end) {
if (start < 0 || end > s.length()) {
throw new StringIndexOutOfBoundsException();
}
if (start == 0 && end == s.length()) {
return s.trim();
}
while (start < end && s.charAt(start) <= ' ') {
start++;
}
while (start < end && s.charAt(end - 1) <= ' ') {
end--;
}
return s.substring(start, end);
}
public static boolean isTrimEmpty(final String s) {
int start= 0;
final int end= s.length();
while (start < end && s.charAt(start) <= ' ') {
start++;
}
return (start == end);
}
public static boolean isTrimEmpty(final String s, int start, final int end) {
if (start < 0 || end > s.length()) {
throw new StringIndexOutOfBoundsException();
}
while (start < end && s.charAt(start) <= ' ') {
start++;
}
return (start == end);
}
public static boolean containsAny(final String s, final ImCollection<String> searchStrings) {
String prevString= null;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
continue;
}
prevString= searchString;
if (s.indexOf(searchString) >= 0) {
return true;
}
}
return false;
}
public static boolean containsAny(final StringBuilder s, final ImCollection<String> searchStrings) {
String prevString= null;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
continue;
}
prevString= searchString;
if (s.indexOf(searchString) >= 0) {
return true;
}
}
return false;
}
public static int firstIndexOfAny(final String s, final ImCollection<String> searchStrings,
final int fromIndex) {
if (fromIndex < 0 || fromIndex > s.length()) {
throw new StringIndexOutOfBoundsException(fromIndex);
}
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
continue;
}
prevString= searchString;
final int index= s.indexOf(searchString, fromIndex);
if (index >= 0 && index < matchIndex) {
matchIndex= index;
}
}
return (matchIndex != Integer.MAX_VALUE) ? matchIndex : -1;
}
public static int firstIndexOfAny(final String s, final ImCollection<String> searchStrings) {
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
continue;
}
prevString= searchString;
final int index= s.indexOf(searchString);
if (index >= 0 && index < matchIndex) {
matchIndex= index;
}
}
return (matchIndex != Integer.MAX_VALUE) ? matchIndex : -1;
}
public static int firstIndexOfAny(final StringBuilder s, final ImCollection<String> searchStrings,
final int fromIndex) {
if (fromIndex < 0 || fromIndex > s.length()) {
throw new StringIndexOutOfBoundsException(fromIndex);
}
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
continue;
}
prevString= searchString;
final int index= s.indexOf(searchString, fromIndex);
if (index >= 0 && index < matchIndex) {
matchIndex= index;
}
}
return (matchIndex != Integer.MAX_VALUE) ? matchIndex : -1;
}
public static int firstIndexOfAny(final StringBuilder s, final ImCollection<String> searchStrings) {
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
continue;
}
prevString= searchString;
final int index= s.indexOf(searchString);
if (index >= 0 && index < matchIndex) {
matchIndex= index;
}
}
return (matchIndex != Integer.MAX_VALUE) ? matchIndex : -1;
}
public static final class Match {
private final String string;
private final int startIndex;
public Match(final String string, final int startIndex) {
this.string= nonNullAssert(string);
this.startIndex= startIndex;
}
public String getString() {
return this.string;
}
public int getStartIndex() {
return this.startIndex;
}
public int getEndIndex() {
return this.startIndex + this.string.length();
}
public int getLength() {
return this.string.length();
}
}
@SuppressWarnings("null")
public static @Nullable Match firstMatchOfAny(final String s, final ImCollection<String> searchStrings,
final int fromIndex) {
if (fromIndex < 0 || fromIndex > s.length()) {
throw new StringIndexOutOfBoundsException(fromIndex);
}
String matchString= null;
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
boolean prevMatch= false;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
if (prevMatch && s.startsWith(searchString, matchIndex)) {
matchString= prevString= searchString;
}
continue;
}
final int index= s.indexOf(searchString, fromIndex);
if (prevMatch= (index >= 0
&& (index < matchIndex
|| index == matchIndex && searchString.length() > matchString.length() ))) {
matchString= searchString;
matchIndex= index;
}
prevString= searchString;
}
return (matchString != null) ? new Match(matchString, matchIndex) : null;
}
@SuppressWarnings("null")
public static @Nullable Match firstMatchOfAny(final String s, final ImCollection<String> searchStrings) {
String matchString= null;
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
boolean prevMatch= false;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
if (prevMatch && s.startsWith(searchString, matchIndex)) {
matchString= searchString;
}
continue;
}
final int index= s.indexOf(searchString);
if (prevMatch= (index >= 0
&& (index < matchIndex
|| index == matchIndex && searchString.length() > matchString.length() ))) {
matchString= searchString;
matchIndex= index;
}
prevString= searchString;
}
return (matchString != null) ? new Match(matchString, matchIndex) : null;
}
@SuppressWarnings("null")
public static @Nullable Match firstMatchOfAny(final StringBuilder s, final ImCollection<String> searchStrings,
final int fromIndex) {
if (fromIndex < 0 || fromIndex > s.length()) {
throw new StringIndexOutOfBoundsException(fromIndex);
}
String matchString= null;
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
boolean prevMatch= false;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
if (prevMatch && matchIndex + searchString.length() <= s.length()
&& s.substring(matchIndex, matchIndex + searchString.length()).equals(searchString) ) {
matchString= prevString= searchString;
}
continue;
}
final int index= s.indexOf(searchString, fromIndex);
if (prevMatch= (index >= 0
&& (index < matchIndex
|| index == matchIndex && searchString.length() > matchString.length() ))) {
matchString= searchString;
matchIndex= index;
}
prevString= searchString;
}
return (matchString != null) ? new Match(matchString, matchIndex) : null;
}
@SuppressWarnings("null")
public static @Nullable Match firstMatchOfAny(final StringBuilder s, final ImCollection<String> searchStrings) {
String matchString= null;
int matchIndex= Integer.MAX_VALUE;
String prevString= null;
boolean prevMatch= false;
for (final String searchString : searchStrings) {
if (prevString != null && searchString.startsWith(prevString)) {
if (prevMatch && matchIndex + searchString.length() <= s.length()
&& s.substring(matchIndex, matchIndex + searchString.length()).equals(searchString) ) {
matchString= prevString= searchString;
}
continue;
}
final int index= s.indexOf(searchString);
if (prevMatch= (index >= 0
&& (index < matchIndex
|| index == matchIndex && searchString.length() > matchString.length() ))) {
matchString= searchString;
matchIndex= index;
}
prevString= searchString;
}
return (matchString != null) ? new Match(matchString, matchIndex) : null;
}
private StringUtils() {
}
}