#java #string #sorting #substring
#java #строка #сортировка #подстрока
Вопрос:
Я в основном программист на Python, немного изучаю Java. Мне нужна была функция для преобразования строк, содержащих имена в форме «First Last», в «Last, First» (мне также нужно это, чтобы иметь возможность обрабатывать отдельные имена: «Cher» => «Cher» и первое среднее последнее: «John F. Kennedy» => «Кеннеди, Джон Ф.»), и я начал думать о решении этого, как я бы сделал в Python:
def tolastfirst(astring):
parts = astring.split()
return parts[-1] ", " " ".join(parts[:-1])
Нарезка строк и разделение списков и объединение настолько распространены и лаконичны в Python, что это было первое, что пришло на ум. Это перевело на Java что-то вроде этого:
public static String toLastFirst(String firstLast) {
List<String> parts = Arrays.asList(firstLast.split(" "));
if (parts.size() > 1) {
String last = parts.get(parts.size() - 1);
List<String> frontParts = parts.subList(0, parts.size() - 1);
String front = org.apache.commons.lang.StringUtils.join(frontParts.toArray(), " ");
return last ", " front;
} else {
return firstLast;
}
}
Так что это кажется излишне сложным, и, вероятно, из кода очевидно, что я не понимаю, почему и для чего используется массив по сравнению со списком. Преобразование из массива в список и обратно казалось глупым, поэтому я попробовал это:
public static String toLastFirst(String firstLast) {
String[] parts = firstLast.split(" ");
if (parts.length > 1) {
String last = parts[parts.length - 1];
String[] frontParts = Arrays.copyOfRange(parts, 0, parts.length - 1);
String front = org.apache.commons.lang.StringUtils.join(frontParts, " ");
return last ", " front;
} else {
return firstLast;
}
}
Наконец, я спросил коллегу, который действительно знает Java, и он предположил, что он, скорее всего, просто найдет последний пробел и разрежет строку, пропустив весь бизнес списка / массива:
public static String toLastFirst(String firstLast) {
if (firstLast.indexOf(" ") != -1) {
Integer lastSpace = firstLast.lastIndexOf(" ");
String first = firstLast.substring(0, lastSpace);
String last = firstLast.substring(lastSpace, firstLast.length());
return last ", " first;
} else {
return firstLast;
}
}
Мои вопросы:
- Правильно ли я интуитивно переключился с использования списка на массив?
- Является ли предложение моего коллеги о прямом манипулировании строками наиболее идиоматичным способом решения этой проблемы в Java?
- Является ли подход к обработке строк более эффективным (память, скорость?) чем подход списка / массива?
В основном меня интересует второй вопрос; Я хотел бы научиться писать Java как родной, а не как экспат Python.
Ответ №1:
Вы можете сделать это намного короче, используя replaceAll()
:
public static String toLastFirst(String firstLast) {
return firstLast.replaceAll("(.*) (.*)", "$2, $1");
}
Это должно работать точно так же, как ваши реализации. Если строка содержит пробел, выражение будет совпадать, и поменяет местами первую и вторую части, и добавит ,
. Если он не содержит пробела, строка остается неизменной.
Комментарии:
1. Я отредактировал вопрос, чтобы отметить, что мой вариант использования включает в себя отдельные имена, такие как «Cher» => «Шер», а также имена со средним именем: «Филип Сеймур Хоффман» => «Хоффман, Филип Сеймур» … охватывает ли ваше решение эти случаи?
2. Изменение регулярного выражения на «(.*) (.*)» делает то, что мне здесь нужно. Прохладный.
3. @ben: Да, я как раз собирался это сказать. 🙂 Делая первую часть жадной, убедитесь, что единственный обмен сделан в последнем пространстве.
Ответ №2:
В общем, когда вам не нужно изменять размер, с массивом может быть проще работать. Вы, конечно, хотите избежать смешивания массивов и списков, попробуйте использовать один или другой, но не смешивать их.
Прямая манипуляция — это то, как я бы решил это, поскольку у вас есть конкретный случай только из двух половин. ответ @ Keppil, вероятно, является самым аккуратным решением Java.
Прямое управление строкой будет немного быстрее, поскольку массив / список не нуждается в создании, инициализации, обновлении и т.д. Разница была бы крошечной в абсолютном выражении, хотя.
Ответ №3:
Вы можете сделать это следующим образом:
public static String toLastFirst(String firstLast) {
//split on one ore more space chars
String[] data = firstLast.split("\s ");
//need to check length of array etc.
return data[1] ", " data[0]; //build new string
}
Комментарии:
1. Распространяется ли это на вариант использования «Филип Сеймур Хоффман» => «Хоффман, Филип Сеймур»?
2. Это очень похоже на мою вторую попытку, нет?
3. @benauthor — для решения этой проблемы рассмотрите возможность циклического перехода
data
отi<data.length-1
кi=0
, создаваяStringBuilder
объект, инициализированный с помощьюdata[data.length-1]