Я обнаружил, что все существующие решения (библиотеки), которые я рассмотрел, страдали одной или несколькими из следующих проблем:
- Они не говорят вам в Javadoc, что именно они заменяют.
- Они избегают слишком много ... что делает HTML намного труднее для чтения.
- Они не документируют , когда возвращаемое значение безопасно использовать (безопасно использовать для сущности HTML ?, для атрибута HTML? И т. Д.)
- Они не оптимизированы для скорости.
- У них нет возможности избежать двойного побега (не избегайте того, что уже сбежало)
- Они заменяют одинарные кавычки на
'
(неправильно!)
Кроме того, у меня также была проблема с невозможностью ввести внешнюю библиотеку, по крайней мере, без определенного количества красной ленты.
Итак, я свернул свой. Guilty.
Ниже это выглядит, но последнюю версию всегда можно найти в этой сущности .
<code>/**
* HTML string utilities
*/
public class SafeHtml {
/**
* Escapes a string for use in an HTML entity or HTML attribute.
*
* <p>
* The returned value is always suitable for an HTML <i>entity</i> but only
* suitable for an HTML <i>attribute</i> if the attribute value is inside
* double quotes. In other words the method is not safe for use with HTML
* attributes unless you put the value in double quotes like this:
* <pre>
* <div title="value-from-this-method" > ....
*
* В любом случае помещать значения атрибутов в двойные кавычки - это всегда хорошая идея.
*
*
Будут экранированы следующие символы:
*
- {@ code &} (амперсанд) - заменено на {@code & amp;}
- {@ code <} (меньше чем) - заменено на {@code & lt;} </li>
*
- {@ code>} (больше чем) - заменено на {@code & gt;}
- {@ code "} (двойная кавычка) - заменено на {@code & quot;}
- {@ code '} (одинарная кавычка) - заменено на {@code'}
- {@ code /} (косая черта) - заменено на {@code /}
* Нет необходимости избегать большего, чем эта, пока HTML-страница
*
использует
* кодировка Unicode . (Большинство веб-страниц использует UTF-8, который также является HTML5
* рекомендация.). Экранирование больше, чем это делает HTML гораздо менее читабельным.
*
* @param s строка, чтобы сделать HTML безопасным
* @param избежатьDoubleEscape избежать двойного побега, что означает, например, не
* избегая {@code & lt;} еще раз. Любая последовательность {@code & ....;}, как описано в
* {@link #isHtmlCharEntityRef (java.lang.String, int) isHtmlCharEntityRef ()} не будет экранирован.
*
* @ вернуть HTML безопасную строку
* /
public static String htmlEscape (String s, логическое избежатьDoubleEscape) {
if (s == null || s.length () == 0) {
возврат с;
}
StringBuilder sb = new StringBuilder (s.length () + 16);
for (int i = 0; i
':
sb.append ( "& GT;");
перерыв;
дело '"':
sb.append ( "& Quot;");
перерыв;
дело '\'':
sb.append ( "'");
перерыв;
дело '/':
sb.append ( "/");
перерыв;
дефолт:
sb.append (с);
}
}
return sb.toString ();
}
/ **
* Проверяет, является ли значение в {@code index} ссылкой на сущность HTML. это
* означает любой из:
*
* {@ code & amp;} или {@code & lt;} или {@code & gt;} или {@code & quot;}
* Значение в форме {@code & # dddd;}, где {@code dddd} - десятичное значение
* Значение в форме {@code & # xhhhh;}, где {@code hhhh} - шестнадцатеричное значение
*
* @param str строка для проверки ссылки на сущность HTML.* @param индексная позиция {@code '&'} в {@code str}
* @вернуть
* /
public static boolean isHtmlCharEntityRef (String str, int index) {
if (str.charAt (index)! = '&') {
вернуть ложь;
}
int indexOfSemicolon = str.indexOf (';', index + 1);
if (indexOfSemicolon == -1) {// есть точка с запятой через некоторое время?
вернуть ложь;
}
if (! (indexOfSemicolon> (index + 2))) {// строка достаточно длинная
вернуть ложь;
}
if (followCharsAre (str, index, "amp;")
|| followCharsAre (str, index, "lt;")
|| followCharsAre (str, index, "gt;")
|| followCharsAre (str, index, "quot;")) {
вернуть истину;
}
if (str.charAt (index + 1) == '#') {
if (str.charAt (index + 2) == 'x' || str.charAt (index + 2) == 'X') {
// Предположительно это шестнадцатеричное значение
if (str.charAt (index + 3) == ';') {
вернуть ложь;
}
for (int i = index + 3; i = 48 && c <= 57) {// 0 - 9
Продолжить;
}
if (c> = 65 && c <= 70) {// A - F
Продолжить;
}
if (c> = 97 && c <= 102) {// a - f
Продолжить;
}
вернуть ложь;
}
вернуть истину; // да, значение является шестнадцатеричной строкой
} еще {
// Предположительно это десятичное значение
for (int i = index + 2; i <indexOfSemicolon; i ++) {
char c = str.charAt (i);
if (c> = 48 && c <= 57) {// 0 - 9
Продолжить;
}
вернуть ложь;
}
вернуть истину; // да, значение десятичное
}
}
вернуть ложь;
}
/ **
* Проверяет, если символы после позиции <code>startIndex в строке
* str
это то, что nextChars
.
*
* Оптимизировано для скорости. В противном случае этот метод был бы точно равен
* {@code (str.indexOf (nextChars, startIndex + 1) == (startIndex + 1))}.
*
* @param str
* @param startIndex
* @param nextChars
* @вернуть
* /
private static boolean followCharsAre (String str, int startIndex, String nextChars) {
if ((startIndex + nextChars.length ())
TODO: сохранить последовательный пробел.