/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.groovy.parser.antlr4.util; import groovy.lang.Closure; import org.apache.groovy.util.Maps; import org.codehaus.groovy.runtime.StringGroovyMethods; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; /** * Utilities for handling strings * * @author <a href="mailto:realbluesun@hotmail.com">Daniel.Sun</a> * Created on 2016/08/20 */ public class StringUtils { public static String replaceHexEscapes(String text) { Pattern p = Pattern.compile("(\\\\*)\\\\u+([0-9abcdefABCDEF]{4})"); return StringGroovyMethods.replaceAll((CharSequence) text, p, new Closure<Void>(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 String replaceOctalEscapes(String text) { Pattern p = Pattern.compile("(\\\\*)\\\\([0-3]?[0-7]?[0-7])"); return StringGroovyMethods.replaceAll((CharSequence) text, p, new Closure<Void>(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))); } }); } private static final Map<Character, Character> STANDARD_ESCAPES = Maps.of( 'b', '\b', 't', '\t', 'n', '\n', 'f', '\f', 'r', '\r' ); public static String replaceStandardEscapes(String text) { Pattern p = Pattern.compile("(\\\\*)\\\\([btnfr\"'])"); String result = StringGroovyMethods.replaceAll((CharSequence) text, p, new Closure<Void>(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); } }); return result.replace("\\\\", "\\"); } 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 = text.replace("\\/", "/"); } if (slashyType == DOLLAR_SLASHY) { text = text.replace("$$", "$"); text = text.replace("$/", "/"); } } else if (slashyType == NONE_SLASHY) { text = StringUtils.replaceEscapes(text); } else { throw new IllegalArgumentException("Invalid slashyType: " + slashyType); } return text; } private static String replaceEscapes(String text) { text = text.replace("\\$", "$"); text = StringUtils.replaceLineEscape(text); return StringUtils.replaceStandardEscapes(replaceHexEscapes(replaceOctalEscapes(text))); } private static String replaceLineEscape(String text) { Pattern p = Pattern.compile("(\\\\*)\\\\\r?\n"); text = StringGroovyMethods.replaceAll((CharSequence) text, p, new Closure<Void>(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 text.replace("\r\n", "\n"); } public static long countChar(String text, char c) { return text.chars().filter(e -> c == e).count(); } }