Теперь, если я хочу преобразовать escape-символы HTML в readable String
меня есть этот метод:
public static String unescapeHTML(String text) {
return text
.replace("™", "")
.replace("€", "€")
.replace(" ", " ")
.replace(" ", " ")
.replace("!", "!")
.replace(""", "\"")
.replace(""", "\"")
.replace("#", "#")
.replace("$", "$")
.replace("%", "%")
.replace("&", "&")
//and the rest of HTML escape characters
.replace("&", "&");
}
Моя цель - не использовать какую-либо внешнюю библиотеку, такую как Apache (class StringUtils
) и т.д. Поскольку список довольно длинный - более 300 символов - было бы неплохо узнать, что было бы самым быстрым способом их замены?
Я решил сделать это так:
private static final Map<Integer, Character> iMap = new HashMap<>();
static {//Code, like   or  
iMap.put(32, ' ');
iMap.put(33, '!');
iMap.put(34, '\"');
iMap.put(35, '#');
iMap.put(36, '$');
iMap.put(37, '%');
iMap.put(38, '&');
//...
}
private static final Map<String, Character> sMap = new HashMap<>();
static {//Entity Name
sMap.put("←", '←');
sMap.put("↑", '↑');
sMap.put("→", '→');
sMap.put("↓", '↓');
sMap.put("↔", '');
sMap.put("♠", '');
sMap.put("♣", '');
sMap.put("♥", '');
//...
}
public static String unescapeHTML(String str) {
StringBuilder sb = new StringBuilder(),
tmp = new StringBuilder();
StringReader sr = new StringReader(str);
boolean esc = false;
try {
int i;
while ((i = sr.read()) != -1) {
char c = (char) i;
if (c == '&') {
tmp.append(c);
esc = true;
} else if (esc) {
tmp.append(c);
if (c == ';') {
esc = false;
if (tmp.charAt(1) == '#') {
try {
sb.append(iMap.get(Integer.parseInt(tmp.substring(2, tmp.capacity() - 1))));
} catch (NumberFormatException ex) {
sb.append(tmp.toString());//Ignore and leave unchanged
}
} else {
sb.append(sMap.get(tmp.toString()));
}
tmp.setLength(0);
}
} else {
sb.append(c);
}
}
sr.close();
} catch (IOException ex) {
Logger.getLogger(UnescapeHTML.class.getName()).log(Level.SEVERE, null, ex);
}
return sb.toString();
}
Работает отлично, и код прост. Все еще тестирование. Было бы неплохо услышать ваши комментарии.
Использование шаблонов и совпадений. если вы хотите избежать вычисления/настройки длины буфера, вы также можете сохранить разницу между двумя строками в некоторой структуре данных и использовать его вместо вычисления длины буфера во время выполнения. например, [-4, -4, 0, -4}. Поскольку длина буфера только возвращает переменную экземпляра, я использовал здесь длину буфера.
private final static Pattern MY_PATTERN = Pattern.compile("\\&(.*?)\\;");
private final static HashMap<String, String> patterns = new HashMap<>();
static{
patterns.put("&", "&");
patterns.put("!", "!");
patterns.put(" ", "thick");
patterns.put("$", "$");
}
public static StringBuffer escapeString(String text){
StringBuffer buffer = new StringBuffer(text);
Matcher m = MY_PATTERN.matcher(text);
int modifiedLength = 0;
while (m.find()) {
int tmpLength = buffer.length();
// To consider the modified buffer length due to replace. hold difference between old and previous
buffer.replace(m.start()-modifiedLength, m.end()-modifiedLength, patterns.get(m.group()));
modifiedLength = modifiedLength + tmpLength-buffer.length();
}
return buffer;
}
'
который иногда может быть написан '
- Я думаю, что более эффективное решение - сравнить целые числа - я разместил здесь тестовую версию.
StringBuilder
и анализироватьString
вручную. Если вы столкнулись с'&'
, то анализируйте до следующих 5 символов или пока не прочитаете';'
, а затем проанализируйте этот символ для ожидаемого символа. Чтобы упростить разработку и поддержку, вы можете сохранить все экранированные строки вMap<String, String>
для удобного сопоставления символов.