Как напечатать строку с символами Юникода без обратной косой черты?

У меня есть следующая строка:

это строка u00c5 с отсутствующей косой чертой перед символами Юникода

Он имеет коды символов Unicode, но все символы обратной косой черты перед «u» отсутствуют. Как правильно напечатать эту строку?

Что я сделал?

Я попытался добавить обратную косую черту перед неполной частью юникода, используя следующий код. Однако "\u$1" не допускается в replaceAll.

public String sanitizeUnicodeQuirk(String input) {
    try {
        // String processedInput = input.replaceAll("[uU]([0123456789abcdefABCDEF]{4})", String.valueOf(Integer.parseInt("$1", 16)));    // $1 is taken literally which makes valuOf and parseInt useless
        String processedInput = input.replaceAll("[uU]([0123456789abcdefABCDEF]{4})", "\\\\u$1");    // Cannot make "\u$1"
        String newInput = new String(processedInput.getBytes(), "UTF-8");
        return newInput;
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    return input;
}

person Mehmed    schedule 27.01.2017    source источник
comment
"u00c5".replaceAll("([uU][0123456789abcdefABCDEF]{4})", "\\\\$1") дает вам \u00c5 в чем проблема? Вам просто нужно удалить u во втором аргументе метода replaceAll.   -  person alain.janinm    schedule 27.01.2017
comment
Преобразование escape-последовательностей Unicode в символы происходит во время компиляции.   -  person Alderath    schedule 27.01.2017
comment
моя ошибка, должно быть [uU](...). Я также не мог заставить его работать по-другому.   -  person Mehmed    schedule 27.01.2017
comment
Возможный дубликат Как отобразить символ валюты из значений utf-8?   -  person Alastair McCormack    schedule 27.01.2017
comment
@Alderath, так что нет другого способа сделать это, кроме как взять четыре шестнадцатеричных кода и преобразовать их в символы, я прав?   -  person Mehmed    schedule 27.01.2017
comment
Возможный дубликат Как преобразовать строка с кодировкой Unicode в строку букв   -  person alain.janinm    schedule 27.01.2017
comment
@Мехмед Наверное, нет. По крайней мере, нельзя полагаться на escape-последовательности Unicode. Предположим, что ваш аргумент input представляет собой строку, которая была прочитана из файла, и эта строка в точности равна Å. Это все равно останется строкой из шести символов Å, а не станет строкой из одного символа с соответствующим символом Юникода. Управляющие последовательности Unicode обрабатываются только во время компиляции и только в том случае, если строка была указана как строковый литерал в исходном коде.   -  person Alderath    schedule 27.01.2017


Ответы (1)


Угу. Доказательство концепции с использованием возможной дублирующей ссылки, предоставленной @AlastairMcCormack в комментариях:

public class Test {
    public static void main(String[] args) {
        String input = "this is the string u0075u0031u0032u0033u0034 with missing slash before unicode characters";
        System.out.println("Original input: " + input);
        Pattern pattern = java.util.regex.Pattern.compile("[uU][0-9a-fA-F]{4}");
        Matcher matcher = pattern.matcher(input);
        StringBuilder builder = new StringBuilder();
        int lastIndex = 0;
        while (matcher.find()) {
               String codePoint = matcher.group().substring(1);
               System.out.println("Found code point: " + codePoint);
               Character charSymbol = (char) Integer.parseInt(codePoint, 16);
               builder.append(input.substring(lastIndex, matcher.start()) + charSymbol);
               lastIndex = matcher.end();
        }
        builder.append(input.substring(lastIndex));
        System.out.println("Modded input: " + builder.toString());
    }
}

Урожайность:

Original input: this is the string u0075u0031u0032u0033u0034 with missing slash before unicode characters
Found code point: 0075
Found code point: 0031
Found code point: 0032
Found code point: 0033
Found code point: 0034
Modded input: this is the string u1234 with missing slash before unicode characters

Имеет смысл, что кодовая точка закодирована как строка символов, и никакая простая очистка с помощью регулярных выражений не исправит это. Это некрасиво, поэтому я был бы очень рад, если бы у кого-то был другой способ.

person Jon Sampson    schedule 27.01.2017
comment
Я не хотел использовать java.util.regex в приложении для Android. Будет ли это слишком обременительно, если я применю это к каждому тексту элемента списка? Есть ли более быстрый способ? - person Mehmed; 27.01.2017
comment
Я не могу говорить конкретно об Android, но я предполагаю, что это действительно вопрос масштаба. Чем больше таких замен вы запустите, тем больше времени это займет, конечно. Если у вас есть контроль над тем, откуда берутся эти элементы представления списка, вы можете просто захотеть перенести как можно больше обработки из клиента Android. Просто примечание на случай, если не очевидно, что ваш метод sanitizeUnicodeQuirk использует String.replaceAll скрывает создание Pattern, Matcher. - person Jon Sampson; 27.01.2017
comment
@Mehmed В реализации String.replaceAll используется java.util.regex. Реализация этой функции: return Pattern.compile(regex).matcher(this).replaceAll(replacement); - person Alderath; 27.01.2017
comment
Изменение строки input, когда вы все еще перебираете ее совпадения, не является хорошей идеей. Вы должны вызвать matcher() только один раз, а затем использовать результаты для создания отдельной переменной string. Это также предотвращает угловой случай исходной строки input, содержащей строку типа u0075u0031u0032u0033u0034, которая декодируется в u1234, а затем следующий вызов matcher() находит это, и она снова декодируется в случайно. Избегайте проблем с двойной заменой в вашем коде, это хороший способ повредить данные. - person Remy Lebeau; 28.01.2017
comment
@RemyLebeau - u0075u0031u0032u0033u0034 действительно прекрасен. Отличная заметка. Для потомков внесу правку. Спасибо! - person Jon Sampson; 28.01.2017
comment
@JonSampson: я бы избавился от переменной Character (почему бы все равно не использовать char?), избавился бы от substring() (вы можете передать индексы непосредственно в append()) и разбил бы append() на два отдельных вызова, чтобы избежать выделения временного string, например: builder.append(input, lastIndex, matcher.start()).append((char) Integer.parseInt(codePoint, 16)); - person Remy Lebeau; 28.01.2017