Как преобразовать произвольную строку в идентификатор Java? - PullRequest
11 голосов
/ 16 сентября 2011

Мне нужно преобразовать любую произвольную строку:

  • строка с пробелами
  • 100stringsstartswithnumber
  • строка € с% специальными † символов / \!
  • [пустая строка]

к действительному идентификатору Java:

  • string_with_spaces
  • _100stringsstartswithnumber
  • string_with_special_characters ___
  • _

Существует ли существующий инструмент для этой задачи?

С таким количеством сред рефакторинга / генерации исходного кода Java можно подумать, что это должно быть довольно распространенной задачей.

Ответы [ 4 ]

11 голосов
/ 16 сентября 2011

Этот простой метод преобразует любую строку ввода в действительный идентификатор Java:

public static String getIdentifier(String str) {
    try {
        return Arrays.toString(str.getBytes("UTF-8")).replaceAll("\\D+", "_");
    } catch (UnsupportedEncodingException e) {
        // UTF-8 is always supported, but this catch is required by compiler
        return null;
    }
}

Пример:

"%^&*\n()" --> "_37_94_38_42_10_56_94_40_41_"

Любые символы ввода будут работать -символы иностранных языков, переводы строк, что угодно!
Кроме того, этот алгоритм:

  • воспроизводимый
  • уникальный - то есть будет всегда и только даст тот же результат, если str1.equals(str2)
  • обратимый

Благодаря Йоахиму Зауэру за предложение UTF-8


Если коллизии в порядке (где две строки ввода могут дать один и тот же результат), этот код создает читаемый вывод:

public static String getIdentifier(String str) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < str.length(); i++) {
        if ((i == 0 && Character.isJavaIdentifierStart(str.charAt(i))) || (i > 0 && Character.isJavaIdentifierPart(str.charAt(i))))
            sb.append(str.charAt(i));
        else
            sb.append((int)str.charAt(i));
    }
    return sb.toString();
}

Он сохраняет символы, которые являются действительными идентификаторами, преобразуя только те, которыенедопустимы в своих десятичных эквивалентах.

3 голосов
/ 16 сентября 2011

Я не знаю инструмент для этой цели, но его легко создать с помощью класса Character.

Знаете ли вы, что строка € with_special_characters ___ является допустимым идентификатором Java?

public class Conv {
    public static void main(String[] args) {
        String[] idents = { "string with spaces", "100stringsstartswithnumber",
                "string€with%special†characters/\\!", "" };
        for (String ident : idents) {
            System.out.println(convert(ident));
        }
    }

    private static String convert(String ident) {
        if (ident.length() == 0) {
            return "_";
        }
        CharacterIterator ci = new StringCharacterIterator(ident);
        StringBuilder sb = new StringBuilder();
        for (char c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) {
            if (c == ' ')
                c = '_';
            if (sb.length() == 0) {
                if (Character.isJavaIdentifierStart(c)) {
                    sb.append(c);
                    continue;
                } else
                    sb.append('_');
            }
            if (Character.isJavaIdentifierPart(c)) {
                sb.append(c);
            } else {
                sb.append('_');
            }
        };
        return sb.toString();
    }
}

Печать

string_with_spaces
_100stringsstartswithnumber
string€with_special_characters___
_
1 голос
/ 16 сентября 2011

С таким большим количеством сред рефакторинга / создания исходного кода Java можно подумать, что это должно быть довольно распространенной задачей.

На самом деле это не так.

  • Структура рефакторинга кода начнется с существующих допустимых идентификаторов Java, будет в состоянии генерировать новый идентификатор, объединяя их с некоторыми дополнительными символами для устранения неоднозначности.

  • Типичная структура генерации кода будетначать с «имен», взятых из ограниченного набора символов.Ему не придется иметь дело с произвольными символами.


Я предполагаю, что целью вашего конвертера является создание идентификаторов, которые напоминают входные строки, если это возможно.Если это так, я бы сделал преобразование, сопоставив все символы допустимого идентификатора как есть, и заменил бы символы недопустимого идентификатора на «$ xxxx», где «xxxx» - это четырехзначное шестнадцатеричное кодирование 16-разрядного символа Java.

Ваша схема тоже работает, но замена всех недопустимых символов на '_' с большей вероятностью приведет к конфликтам идентификаторов;т.е. где две входные строки отображаются на один и тот же идентификатор.

Это просто для кода, поэтому я оставлю это для вас.

1 голос
/ 16 сентября 2011

Если вы делаете это для автоматически сгенерированного кода (то есть не особо заботитесь о читабельности), то один из моих любимых вариантов - просто Base64 . Не нужно разбираться в языке юристов о том, какие символы допустимы в каких кодировках, и это довольно распространенный способ «защиты» произвольных байтовых данных.

...