Как преобразовать произвольную строку в идентификатор Java?
Мне нужно преобразовать любую произвольную строку:
- строку с пробелами
- 100stringsstartswithnumber
- строка€со специальными символами%†/!
- [пустая строка]
к действительному идентификатору Java:
- string_with_spaces
- _100stringsstartswithnumber
- строка_с_специальный_символы___
- _
есть ли существующий инструмент для этого задач?
с таким количеством Java-источников рефакторинга / генерации фреймворков можно было бы подумать, что это должна быть довольно распространенная задача.
4 ответов
этот простой метод преобразования любой входная строка в допустимый идентификатор 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_"
любые входные символы будут работать-символы иностранного языка, linefeeds, что угодно!
Кроме того, этот алгоритм:
- воспроизводимость
- уникальный-ie будет всегда и только произвести тот же результат, если
str1.equals(str2)
- реверсивные
спасибо Йоахим Зауэр на UTF-8
предложение
если коллизии в порядке (где возможно, чтобы две входные строки давали один и тот же результат), этот код выдает читаемый вывод:
public static String getIdentifier(String str) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
if (Character.isJavaIdentifierStart(str.charAt(0)) || i > 0 && Character.isJavaIdentifierPart(str.charAt(i)))
sb.append(str.charAt(i));
else
sb.append((int)str.charAt(i));
}
return sb.toString();
}
Он сохраняет символы, которые являются допустимыми идентификаторами, преобразовывать только те, которые являются недопустимыми в их десятичные эквиваленты.
Я не знаю инструмента для этой цели, но его можно легко создать с помощью класса символов.
знаете ли вы, что строка€с_специальными_символами___ является юридическим идентификатором 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___
_
Если вы делаете это автоматически сформированный код (т. е. не заботятся о читабельности) одна из моих любимых, это просто в base64 его. Нет необходимости играть в language lawyer над тем, какие символы действительны в каких кодировках, и это довольно распространенный способ "защиты" произвольных байтовых данных.
С таким количеством Java-источников рефакторинга / генерации фреймворков можно было бы подумать, что это должна быть довольно распространенная задача.
на самом деле это не так.
структура рефакторинга кода начнется с существующих допустимых идентификаторов java, сможет генерировать новый идентификатор, объединяя их с некоторыми дополнительными символами для целей устранения неоднозначности.
начнется типичная структура генерации кода с "именами", взятыми из ограниченного набора символов. Ему не придется иметь дело с произвольными символами.
Я предполагаю, что целью вашего конвертера является создание идентификаторов, которые напоминают входные строки, если это возможно. Если это так, я бы сделал преобразование, сопоставив все законные символы идентификатора как есть и заменив незаконные символы идентификатора на "$xxxx", где "xxxx" - это 4-значная шестнадцатиразрядная кодировка Java 16-бит характер.
ваша схема тоже работает, но замена всех незаконных символов на " _ " с большей вероятностью приведет к коллизиям идентификаторов; т. е. где две входные строки сопоставляются с одним и тем же идентификатором.
это прямолинейно для кода, поэтому я оставлю это для вас.