Эффективный способ удаления экранирующих символов HTML БЕЗ внешней библиотеки

0

Теперь, если я хочу преобразовать 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 символов - было бы неплохо узнать, что было бы самым быстрым способом их замены?

  • 1
    Этот подход занял бы слишком много времени выполнения. Я бы сказал, чтобы использовать StringBuilder и анализировать String вручную. Если вы столкнулись с '&' , то анализируйте до следующих 5 символов или пока не прочитаете ';' , а затем проанализируйте этот символ для ожидаемого символа. Чтобы упростить разработку и поддержку, вы можете сохранить все экранированные строки в Map<String, String> для удобного сопоставления символов.
  • 0
    Хм .. Я должен сделать некоторое тестирование.
Показать ещё 2 комментария
Теги:
string
escaping

2 ответа

0

Я решил сделать это так:

    private static final Map<Integer, Character> iMap = new HashMap<>();

    static {//Code, like &#32; or &#032;
        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("&larr;", '←');
        sMap.put("&uarr;", '↑');
        sMap.put("&rarr;", '→');
        sMap.put("&darr;", '↓');
        sMap.put("&harr;", '');
        sMap.put("&spades;", '');
        sMap.put("&clubs;", '');
        sMap.put("&hearts;", '');
        //...
    }

    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();
    }

Работает отлично, и код прост. Все еще тестирование. Было бы неплохо услышать ваши комментарии.

0

Использование шаблонов и совпадений. если вы хотите избежать вычисления/настройки длины буфера, вы также можете сохранить разницу между двумя строками в некоторой структуре данных и использовать его вместо вычисления длины буфера во время выполнения. например, [-4, -4, 0, -4}. Поскольку длина буфера только возвращает переменную экземпляра, я использовал здесь длину буфера.

private final static Pattern MY_PATTERN = Pattern.compile("\\&(.*?)\\;");
    private final static HashMap<String, String> patterns = new HashMap<>();
    static{
        patterns.put("&amp;", "&");
        patterns.put("&#33;", "!");
        patterns.put("&#32;", "thick");
        patterns.put("&#36;", "$");
    }

    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;
    }
  • 0
    Из-за &#39; который иногда может быть написан &#039; - Я думаю, что более эффективное решение - сравнить целые числа - я разместил здесь тестовую версию.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню