StringFunctions.java
/*
* Copyright 2021 Dominik Kopczynski, Nils Hoffmann.
*
* 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 org.lifstools.jgoslin.domain;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* Utility methods for strings and grammars.
*
* @author Dominik Kopczynski
* @author Nils Hoffmann
*/
public final class StringFunctions {
public static char DEFAULT_QUOTE = '\'';
public static char DEFAULT_SPLIT = ',';
private StringFunctions(){};
public static String strip(String s, char c) {
if (s.length() > 0) {
int st = 0;
while (st < s.length() - 1 && s.charAt(st) == c) {
++st;
}
s = s.substring(st, s.length());
}
if (s.length() > 0) {
int en = 0;
while (en < s.length() - 1 && s.charAt(s.length() - 1 - en) == c) {
++en;
}
s = s.substring(0, s.length() - en);
}
return s;
}
/**
* Split the provided text at {@link #DEFAULT_SPLIT} as separator, using
* {@link #DEFAULT_QUOTE} as the default quotation char.
*
* @param text the text to split
* @return the split string as a list
*/
public static ArrayList<String> splitString(String text) {
return splitString(text, DEFAULT_SPLIT, DEFAULT_QUOTE, false);
}
/**
* Split the provided text at separator, respecting the quote char to not
* split in between quoted parts.
*
* @param text the text to split
* @param separator the separator to split at
* @param quote the quotation character
* @return the split string as a list
*/
public static ArrayList<String> splitString(String text, char separator, char quote) {
return splitString(text, separator, quote, false);
}
/**
* Split the provided text at separator, respecting the quote char to not
* split in between quoted parts. Optionally allow empty / whitespace at the
* end.
*
* @param text the text to split
* @param separator the separator to split at
* @param quote the quotation character
* @param withEmpty if true, allow empty parts
* @return the split string as a list
*/
public static ArrayList<String> splitString(String text, char separator, char quote, boolean withEmpty) {
boolean in_quote = false;
ArrayList<String> tokens = new ArrayList<>();
StringBuilder sb = new StringBuilder();
char last_char = '\0';
boolean last_escaped_backslash = false;
for (int i = 0; i < text.length(); ++i) {
char c = text.charAt(i);
boolean escaped_backslash = false;
if (!in_quote) {
if (c == separator) {
String sb_string = sb.toString();
if (sb_string.length() > 0 || withEmpty) {
tokens.add(sb_string);
}
sb = new StringBuilder();
} else {
if (c == quote) {
in_quote = !in_quote;
}
sb.append(c);
}
} else {
if (c == '\\' && last_char == '\\' && !last_escaped_backslash) {
escaped_backslash = true;
} else if (c == quote && !(last_char == '\\' && !last_escaped_backslash)) {
in_quote = !in_quote;
}
sb.append(c);
}
last_escaped_backslash = escaped_backslash;
last_char = c;
}
String sb_string_end = sb.toString();
if (sb_string_end.length() > 0 || (last_char == ',' && withEmpty)) {
tokens.add(sb_string_end);
}
if (in_quote) {
throw new ConstraintViolationException("Error: corrupt token in grammar: '" + sb_string_end+"'");
}
return tokens;
}
/**
* Read the provided resource and split it at default new line characters
* into a list for each line.
*
* @param resource the resource to read
* @return a list of line strings
*/
public static List<String> getResourceAsStringList(Resource resource) {
ArrayList<String> lines;
// read resource from classpath and current thread's context class loader
try (BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
lines = br.lines().collect(Collectors.toCollection(ArrayList::new));
} catch (IOException e) {
//always pass on the original exception
throw new ConstraintViolationException("Error: Resource '" + resource.getDescription() + "' does not exist.", e);
}
return lines;
}
/**
* Read the provided resource path, which is converted to a
* {@link ClassPathResource} and split it at default new line characters
* into a list for each line.
*
* @param resourcePath the resource path to read from
* @return a list of line strings
*/
public static List<String> getResourceAsStringList(String resourcePath) {
return getResourceAsStringList(new ClassPathResource(resourcePath));
}
/**
* Read the provided resource and return it as a string.
*
* @param resource the resource to read
* @return the resource content as a string
*/
public static String getResourceAsString(Resource resource) {
StringBuilder sb = new StringBuilder();
// read resource from classpath and current thread's context class loader
try (BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
br.lines().forEach(line -> {
sb.append(line).append("\n");
});
return sb.toString();
} catch (IOException e) {
//always pass on the original exception
throw new ConstraintViolationException("Error: Resource '" + resource.getDescription() + "' does not exist.", e);
}
}
/**
* Read the provided resource path and return it as a string.
*
* @param resourcePath the resource path to read from
* @return the resource content as a string
*/
public static String getResourceAsString(String resourcePath) {
return getResourceAsString(new ClassPathResource(resourcePath));
}
}