diff --git a/src/main/java/org/apache/groovy/parser/antlr4/util/StringUtils.java b/src/main/java/org/apache/groovy/parser/antlr4/util/StringUtils.java index d4fc339e1c1..a312eeed7b4 100644 --- a/src/main/java/org/apache/groovy/parser/antlr4/util/StringUtils.java +++ b/src/main/java/org/apache/groovy/parser/antlr4/util/StringUtils.java @@ -20,143 +20,57 @@ import groovy.lang.Closure; import org.apache.groovy.util.Maps; -import org.codehaus.groovy.runtime.StringGroovyMethods; import java.util.Map; import java.util.regex.Pattern; +import static org.codehaus.groovy.runtime.StringGroovyMethods.replaceAll; + /** * Utilities for handling strings * */ public class StringUtils { - private static final String BACKSLASH = "\\"; - private static final Pattern HEX_ESCAPES_PATTERN = Pattern.compile("(\\\\*)\\\\u([0-9abcdefABCDEF]{4})"); - private static final Pattern OCTAL_ESCAPES_PATTERN = Pattern.compile("(\\\\*)\\\\([0-3]?[0-7]?[0-7])"); - private static final Pattern STANDARD_ESCAPES_PATTERN = Pattern.compile("(\\\\*)\\\\([btnfrs\"'])"); - private static final Pattern LINE_ESCAPE_PATTERN = Pattern.compile("(\\\\*)\\\\\r?\n"); - - public static String replaceHexEscapes(String text) { - if (!text.contains(BACKSLASH)) { - return text; - } - - return StringGroovyMethods.replaceAll((CharSequence) text, HEX_ESCAPES_PATTERN, new Closure(null, null) { - Object doCall(String _0, String _1, String _2) { - if (isLengthOdd(_1)) { - return _0; - } - - return _1 + new String(Character.toChars(Integer.parseInt(_2, 16))); - } - }); + public static final int NONE_SLASHY = 0; + public static final int SLASHY = 1; + public static final int DOLLAR_SLASHY = 2; + + public static String replaceEscapes(String text, int slashyType) { + if (slashyType == SLASHY || slashyType == DOLLAR_SLASHY) { + text = StringUtils.replaceHexEscapes(text); + text = StringUtils.replaceLineEscape(text); + + if (slashyType == SLASHY) { + text = replace(text,"\\/", "/"); + } else if (slashyType == DOLLAR_SLASHY) { + text = replace(text,"$/", "/"); + text = replace(text,"$$", "$"); + } + } else if (slashyType == NONE_SLASHY) { + text = StringUtils.replaceEscapes(text); + } else { + throw new IllegalArgumentException("Invalid slashyType: " + slashyType); + } + + return text; + } + + public static String replaceHexEscapes(String text) { + if (!text.contains(BACKSLASH)) return text; + return replaceAll((CharSequence) text, HEX_ESCAPES_PATTERN, REPLACE_HEX_ESCAPES); } public static String replaceOctalEscapes(String text) { - if (!text.contains(BACKSLASH)) { - return text; - } - - return StringGroovyMethods.replaceAll((CharSequence) text, OCTAL_ESCAPES_PATTERN, new Closure(null, null) { - Object doCall(String _0, String _1, String _2) { - if (isLengthOdd(_1)) { - return _0; - } - - return _1 + new String(Character.toChars(Integer.parseInt(_2, 8))); - } - }); + if (!text.contains(BACKSLASH)) return text; + return replaceAll((CharSequence) text, OCTAL_ESCAPES_PATTERN, REPLACE_OCTAL_ESCAPES); } - private static final Map STANDARD_ESCAPES = Maps.of( - 'b', '\b', - 't', '\t', - 'n', '\n', - 'f', '\f', - 'r', '\r', - 's', ' ' - ); - - public static String replaceStandardEscapes(String text) { - if (!text.contains(BACKSLASH)) { - return text; - } - - String result = StringGroovyMethods.replaceAll((CharSequence) text, STANDARD_ESCAPES_PATTERN, new Closure(null, null) { - Object doCall(String _0, String _1, String _2) { - if (isLengthOdd(_1)) { - return _0; - } - - Character character = STANDARD_ESCAPES.get(_2.charAt(0)); - return _1 + (character != null ? character : _2); - } - }); - + public static String replaceStandardEscapes(String text) { + if (!text.contains(BACKSLASH)) return text; + final String result = replaceAll((CharSequence) text, STANDARD_ESCAPES_PATTERN, REPLACE_STANDARD_ESCAPES); return replace(result,"\\\\", "\\"); } - public static final int NONE_SLASHY = 0; - public static final int SLASHY = 1; - public static final int DOLLAR_SLASHY = 2; - - public static String replaceEscapes(String text, int slashyType) { - if (slashyType == SLASHY || slashyType == DOLLAR_SLASHY) { - text = StringUtils.replaceHexEscapes(text); - text = StringUtils.replaceLineEscape(text); - - if (slashyType == SLASHY) { - text = replace(text,"\\/", "/"); - } - - if (slashyType == DOLLAR_SLASHY) { - text = replace(text,"$/", "/"); - text = replace(text,"$$", "$"); - } - - } else if (slashyType == NONE_SLASHY) { - text = StringUtils.replaceEscapes(text); - } else { - throw new IllegalArgumentException("Invalid slashyType: " + slashyType); - } - - return text; - } - - private static String replaceEscapes(String text) { - if (!text.contains(BACKSLASH)) { - return text; - } - - text = replace(text,"\\$", "$"); - - text = StringUtils.replaceLineEscape(text); - - return StringUtils.replaceStandardEscapes(replaceHexEscapes(replaceOctalEscapes(text))); - } - - private static String replaceLineEscape(String text) { - if (!text.contains(BACKSLASH)) { - return text; - } - - text = StringGroovyMethods.replaceAll((CharSequence) text, LINE_ESCAPE_PATTERN, new Closure(null, null) { - Object doCall(String _0, String _1) { - if (isLengthOdd(_1)) { - return _0; - } - - return _1; - } - }); - - return text; - } - - private static boolean isLengthOdd(String str) { - return null != str && str.length() % 2 == 1; - } - public static String removeCR(String text) { return replace(text,"\r\n", "\n"); } @@ -167,7 +81,6 @@ public static long countChar(String text, char c) { public static String trimQuotations(String text, int quotationLength) { int length = text.length(); - return length == quotationLength << 1 ? "" : text.substring(quotationLength, length - quotationLength); } @@ -200,9 +113,8 @@ public static boolean matches(String text, Pattern pattern) { * {@code null} if null String input */ public static String replace(final String text, String searchString, final String replacement) { - if (isEmpty(text) || isEmpty(searchString) || replacement == null) { - return text; - } + if (isEmpty(text) || isEmpty(searchString) || replacement == null) return text; + int start = 0; int end = text.indexOf(searchString, start); if (end == INDEX_NOT_FOUND) { @@ -245,10 +157,65 @@ public static boolean isEmpty(final CharSequence cs) { return cs == null || cs.length() == 0; } - /** + private static String replaceEscapes(String text) { + if (!text.contains(BACKSLASH)) return text; + text = replace(text,"\\$", "$"); + text = StringUtils.replaceLineEscape(text); + return StringUtils.replaceStandardEscapes(replaceHexEscapes(replaceOctalEscapes(text))); + } + + private static String replaceLineEscape(String text) { + if (!text.contains(BACKSLASH)) return text; + text = replaceAll((CharSequence) text, LINE_ESCAPE_PATTERN, REPLACE_LINE_ESCAPE); + return text; + } + + private static boolean isLengthOdd(String str) { + return null != str && str.length() % 2 == 1; + } + + /** * Copied from Apache commons-lang3-3.6 * * Represents a failed index search. */ private static final int INDEX_NOT_FOUND = -1; -} \ No newline at end of file + private static final String BACKSLASH = "\\"; + private static final Pattern HEX_ESCAPES_PATTERN = Pattern.compile("(\\\\*)\\\\u([0-9abcdefABCDEF]{4})"); + private static final Pattern OCTAL_ESCAPES_PATTERN = Pattern.compile("(\\\\*)\\\\([0-3]?[0-7]?[0-7])"); + private static final Pattern STANDARD_ESCAPES_PATTERN = Pattern.compile("(\\\\*)\\\\([btnfrs\"'])"); + private static final Pattern LINE_ESCAPE_PATTERN = Pattern.compile("(\\\\*)\\\\\r?\n"); + private static final Map STANDARD_ESCAPES = Maps.of( + 'b', '\b', + 't', '\t', + 'n', '\n', + 'f', '\f', + 'r', '\r', + 's', ' ' + ); + private static final Closure REPLACE_STANDARD_ESCAPES = new Closure(null, null) { + String doCall(String _0, String _1, String _2) { + if (isLengthOdd(_1)) return _0; + final Character character = STANDARD_ESCAPES.get(_2.charAt(0)); + return _1 + (character != null ? character : _2); + } + }; + private static final Closure REPLACE_OCTAL_ESCAPES = new Closure(null, null) { + String doCall(String _0, String _1, String _2) { + if (isLengthOdd(_1)) return _0; + return _1 + new String(Character.toChars(Integer.parseInt(_2, 8))); + } + }; + private static final Closure REPLACE_HEX_ESCAPES = new Closure(null, null) { + String doCall(String _0, String _1, String _2) { + if (isLengthOdd(_1)) return _0; + return _1 + new String(Character.toChars(Integer.parseInt(_2, 16))); + } + }; + private static final Closure REPLACE_LINE_ESCAPE = new Closure(null, null) { + String doCall(String _0, String _1) { + if (isLengthOdd(_1)) return _0; + return _1; + } + }; +}