cleanup: Use jsoup xml escaper

This commit is contained in:
tarsin committed 2023-02-18 11:44:55 +08:00
1 parent cf87a654fb
commit 41b818caa6
2 files changed
+6 -265

No files matched your search

@@ -18,6 +18,8 @@ package com.hippo.yorozuya;
import android.text.TextUtils;
import org.jsoup.parser.Parser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -30,25 +32,6 @@ public final class StringUtils {
'\u00A0', // NO-BREAK SPACE
'\u3000', // IDEOGRAPHIC SPACE
};
private static final String[] ESCAPE_CHARATER_LIST = {
"&",
"<",
">",
""",
"'",
"×",
" "
};
private static final String[] UNESCAPE_CHARATER_LIST = {
"&",
"<",
">",
"\"",
"'",
"×",
" "
};
private StringUtils() {
}
@@ -57,7 +40,7 @@ public final class StringUtils {
* Unescape xml. It do not work perfectly.
*/
public static String unescapeXml(String str) {
return replaceEach(str, ESCAPE_CHARATER_LIST, UNESCAPE_CHARATER_LIST);
return Parser.unescapeEntities(str, true);
}
/**
@@ -141,218 +124,6 @@ public final class StringUtils {
return buf.toString();
}
/**
* <p>
* Replaces all occurrences of Strings within another String.
* </p>
*
* <p>
* A {@code null} reference passed to this method is a no-op, or if
* any "search string" or "string to replace" is null, that replace will be
* ignored. This will not repeat. For repeating replaces, call the
* overloaded method.
* </p>
*
* <pre>
* StringUtils.replaceEach(null, *, *) = null
* StringUtils.replaceEach("", *, *) = ""
* StringUtils.replaceEach("aba", null, null) = "aba"
* StringUtils.replaceEach("aba", new String[0], null) = "aba"
* StringUtils.replaceEach("aba", null, new String[0]) = "aba"
* StringUtils.replaceEach("aba", new String[]{"a"}, null) = "aba"
* StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}) = "b"
* StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}) = "aba"
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}) = "wcte"
* (example of how it does not repeat)
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}) = "dcte"
* </pre>
*
* @param text text to search and replace in, no-op if null
* @param searchList the Strings to search for, no-op if null
* @param replacementList the Strings to replace them with, no-op if null
* @return the text with any replacements processed, {@code null} if
* null String input
* @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok,
* and/or size 0)
*/
// Get from org.apache.commons.lang3.StringUtils
public static String replaceEach(final String text, final String[] searchList,
final String[] replacementList) {
return replaceEach(text, searchList, replacementList, false, 0);
}
/**
* <p>
* Replaces all occurrences of Strings within another String.
* </p>
*
* <p>
* A {@code null} reference passed to this method is a no-op, or if
* any "search string" or "string to replace" is null, that replace will be
* ignored.
* </p>
*
* <pre>
* StringUtils.replaceEach(null, *, *, *) = null
* StringUtils.replaceEach("", *, *, *) = ""
* StringUtils.replaceEach("aba", null, null, *) = "aba"
* StringUtils.replaceEach("aba", new String[0], null, *) = "aba"
* StringUtils.replaceEach("aba", null, new String[0], *) = "aba"
* StringUtils.replaceEach("aba", new String[]{"a"}, null, *) = "aba"
* StringUtils.replaceEach("aba", new String[]{"a"}, new String[]{""}, *) = "b"
* StringUtils.replaceEach("aba", new String[]{null}, new String[]{"a"}, *) = "aba"
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"w", "t"}, *) = "wcte"
* (example of how it repeats)
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, false) = "dcte"
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "t"}, true) = "tcte"
* StringUtils.replaceEach("abcde", new String[]{"ab", "d"}, new String[]{"d", "ab"}, *) = IllegalStateException
* </pre>
*
* @param text text to search and replace in, no-op if null
* @param searchList the Strings to search for, no-op if null
* @param replacementList the Strings to replace them with, no-op if null
* @param repeat if true, then replace repeatedly
* until there are no more possible replacements or timeToLive < 0
* @param timeToLive if less than 0 then there is a circular reference and endless
* loop
* @return the text with any replacements processed, {@code null} if
* null String input
* @throws IllegalStateException if the search is repeating and there is an endless loop due
* to outputs of one being inputs to another
* @throws IllegalArgumentException if the lengths of the arrays are not the same (null is ok,
* and/or size 0)
*/
// Get from org.apache.commons.lang3.StringUtils
private static String replaceEach(
final String text, final String[] searchList,
final String[] replacementList, final boolean repeat,
final int timeToLive) {
// mchyzer Performance note: This creates very few new objects (one major goal)
// let me know if there are performance requests, we can create a harness to measure
if (text == null || TextUtils.isEmpty(text) || searchList == null ||
searchList.length == 0 || replacementList == null || replacementList.length == 0) {
return text;
}
// if recursing, this shouldn't be less than 0
if (timeToLive < 0) {
throw new IllegalStateException("Aborting to protect against StackOverflowError - " +
"output of one loop is the input of another");
}
final int searchLength = searchList.length;
final int replacementLength = replacementList.length;
// make sure lengths are ok, these need to be equal
if (searchLength != replacementLength) {
throw new IllegalArgumentException("Search and Replace array lengths don't match: "
+ searchLength
+ " vs "
+ replacementLength);
}
// keep track of which still have matches
final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength];
// index on index that the match was found
int textIndex = -1;
int replaceIndex = -1;
int tempIndex = -1;
// index of replace array that will replace the search string found
// NOTE: logic duplicated below START
for (int i = 0; i < searchLength; i++) {
if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
TextUtils.isEmpty(searchList[i]) || replacementList[i] == null) {
continue;
}
tempIndex = text.indexOf(searchList[i]);
// see if we need to keep searching for this
if (tempIndex == -1) {
noMoreMatchesForReplIndex[i] = true;
} else {
if (textIndex == -1 || tempIndex < textIndex) {
textIndex = tempIndex;
replaceIndex = i;
}
}
}
// NOTE: logic mostly below END
// no search strings found, we are done
if (textIndex == -1) {
return text;
}
int start = 0;
// get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit
int increase = 0;
// count the replacement text elements that are larger than their corresponding text being replaced
for (int i = 0; i < searchList.length; i++) {
if (searchList[i] == null || replacementList[i] == null) {
continue;
}
final int greater = replacementList[i].length() - searchList[i].length();
if (greater > 0) {
increase += 3 * greater; // assume 3 matches
}
}
// have upper-bound at 20% increase, then let Java take over
increase = Math.min(increase, text.length() / 5);
final StringBuilder buf = new StringBuilder(text.length() + increase);
while (textIndex != -1) {
for (int i = start; i < textIndex; i++) {
buf.append(text.charAt(i));
}
buf.append(replacementList[replaceIndex]);
start = textIndex + searchList[replaceIndex].length();
textIndex = -1;
replaceIndex = -1;
tempIndex = -1;
// find the next earliest match
// NOTE: logic mostly duplicated above START
for (int i = 0; i < searchLength; i++) {
if (noMoreMatchesForReplIndex[i] || searchList[i] == null ||
TextUtils.isEmpty(searchList[i]) || replacementList[i] == null) {
continue;
}
tempIndex = text.indexOf(searchList[i], start);
// see if we need to keep searching for this
if (tempIndex == -1) {
noMoreMatchesForReplIndex[i] = true;
} else {
if (textIndex == -1 || tempIndex < textIndex) {
textIndex = tempIndex;
replaceIndex = i;
}
}
}
// NOTE: logic duplicated above END
}
final int textLength = text.length();
for (int i = start; i < textLength; i++) {
buf.append(text.charAt(i));
}
final String result = buf.toString();
if (!repeat) {
return result;
}
return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1);
}
public static boolean endsWith(String string, String[] suffixs) {
for (int i = 0, n = suffixs.length; i < n; i++) {
if (string.endsWith(suffixs[i])) {
@@ -464,38 +235,6 @@ public final class StringUtils {
return null == str ? 0 : str.length();
}
/**
* <p>Counts how many times the char appears in the given string.</p>
*
* <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
*
* <pre>
* StringUtils.countMatches(null, *) = 0
* StringUtils.countMatches("", *) = 0
* StringUtils.countMatches("abba", 0) = 0
* StringUtils.countMatches("abba", 'a') = 2
* StringUtils.countMatches("abba", 'b') = 2
* StringUtils.countMatches("abba", 'x') = 0
* </pre>
*
* @param str the CharSequence to check, may be null
* @param ch the char to count
* @return the number of occurrences, 0 if the CharSequence is {@code null}
*/
public static int countMatches(final CharSequence str, final char ch) {
if (TextUtils.isEmpty(str)) {
return 0;
}
int count = 0;
// We could also call str.toCharArray() for faster look ups but that would generate more garbage.
for (int i = 0; i < str.length(); i++) {
if (ch == str.charAt(i)) {
count++;
}
}
return count;
}
/**
* All null or empty, or all not
*/
@@ -1,5 +1,7 @@
package com.hippo.yorozuya
import org.jsoup.parser.Parser
fun String.unescapeXml(): String {
return StringUtils.unescapeXml(this)
return Parser.unescapeEntities(this, true)
}