Самый эффективный способ сделать первый символ строчной строчки?
Каков наиболее эффективный способ сделать первый символ нижнего регистра String
?
Я могу придумать несколько способов сделать это:
Используя charAt()
с substring()
String input = "SomeInputString";
String output = Character.toLowerCase(input.charAt(0)) +
(input.length() > 1 ? input.substring(1) : "");
Или используя массив char
String input = "SomeInputString";
char c[] = input.toCharArray();
c[0] = Character.toLowerCase(c[0]);
String output = new String(c);
Я уверен, что есть много других отличных способов достижения этого. Что вы рекомендуете?
Ответы
Ответ 1
Я тестировал многообещающие подходы, используя JMH. Полный тест code.
Предположение во время тестов (во избежание проверки угловых случаев каждый раз): длина строки для строки всегда больше 1.
Результаты
Benchmark Mode Cnt Score Error Units
MyBenchmark.test1 thrpt 20 10463220.493 ± 288805.068 ops/s
MyBenchmark.test2 thrpt 20 14730158.709 ± 530444.444 ops/s
MyBenchmark.test3 thrpt 20 16079551.751 ± 56884.357 ops/s
MyBenchmark.test4 thrpt 20 9762578.446 ± 584316.582 ops/s
MyBenchmark.test5 thrpt 20 6093216.066 ± 180062.872 ops/s
MyBenchmark.test6 thrpt 20 2104102.578 ± 18705.805 ops/s
Оценка - это операции в секунду, тем лучше, тем лучше.
Испытания
-
test1
был первым подходом Энди и Hllink:
string = Character.toLowerCase(string.charAt(0)) + string.substring(1);
-
test2
был вторым подходом Энди. Это также Introspector.decapitalize()
, предложенное Даниэлем, но без двух if
операторов. Первый if
был удален из-за предположения тестирования. Второй был удален, потому что он нарушал правильность (т.е. Вход "HI"
возвращался "HI"
). Это было почти самым быстрым.
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
string = new String(c);
-
test3
была модификацией test2
, но вместо Character.toLowerCase()
я добавлял 32, который корректно работает тогда и только тогда, когда строка находится в ASCII. Это было самым быстрым. c[0] |= ' '
от Mike comment дал ту же производительность.
char c[] = string.toCharArray();
c[0] += 32;
string = new String(c);
-
test4
используется StringBuilder
.
StringBuilder sb = new StringBuilder(string);
sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
string = sb.toString();
-
test5
использовали два вызова substring()
.
string = string.substring(0, 1).toLowerCase() + string.substring(1);
-
test6
использует отражение для изменения char value[]
непосредственно в String. Это был самый медленный.
try {
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
char[] value = (char[]) field.get(string);
value[0] = Character.toLowerCase(value[0]);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
Выводы
Если длина строки всегда больше 0, используйте test2
.
Если нет, мы должны проверить угловые случаи:
public static String decapitalize(String string)
if (string == null || string.length() == 0) {
return string;
}
char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
return new String(c);
}
Если вы уверены, что ваш текст будет всегда в ASCII, и вы ищете экстремальную производительность, потому что вы нашли этот код в узком месте, используйте test3
.
Ответ 2
Я столкнулся с хорошей альтернативой, если вы не хотите использовать стороннюю библиотеку:
import java.beans.Introspector;
Assert.assertEquals("someInputString", Introspector.decapitalize("SomeInputString"));
Ответ 3
Когда дело доходит до строковых манипуляций, посмотрите на Jakarta Commons Lang StringUtils.
Ответ 4
Если вы хотите использовать Apache Commons, вы можете сделать следующее:
import org.apache.commons.lang3.text.WordUtils;
[...]
String s = "SomeString";
String firstLower = WordUtils.uncapitalize(s);
Результат: someString
Ответ 5
Несмотря на ориентированный на char подход, я бы предложил String-ориентированное решение.
String.toLowerCase специфичен для локали, поэтому я буду учитывать эту проблему. String.toLowerCase
предпочтительнее использовать нижний регистр в соответствии с Character.toLowerCase.
Кроме того, ориентированное char решение не полностью совместимо с юникодом, потому что Character.toLowerCase не может обрабатывать дополнительные символы.
public static final String uncapitalize(final String originalStr,
final Locale locale) {
final int splitIndex = 1;
final String result;
if (originalStr.isEmpty()) {
result = originalStr;
} else {
final String first = originalStr.substring(0, splitIndex).toLowerCase(
locale);
final String rest = originalStr.substring(splitIndex);
final StringBuilder uncapStr = new StringBuilder(first).append(rest);
result = uncapStr.toString();
}
return result;
}
UPDATE:
В качестве примера, насколько важна настройка языкового стандарта, введите I
в турецкий и немецкий языки:
System.out.println(uncapitalize("I", new Locale("TR","tr")));
System.out.println(uncapitalize("I", new Locale("DE","de")));
выдаст два разных результата:
я
Ответ 6
Строки в Java неизменяемы, поэтому в любом случае будет создана новая строка.
Ваш первый пример, вероятно, будет немного более эффективным, потому что ему нужно только создать новую строку, а не временный массив символов.
Ответ 7
Очень короткий и простой статический метод для архивирования того, что вы хотите:
public static String decapitalizeString(String string) {
return string == null || string.isEmpty() ? "" : Character.toLowerCase(string.charAt(0)) + string.substring(1);
}
Ответ 8
Если вам нужно очень просто (например, имена классов java, никаких локалей), вы также можете использовать класс CaseFormat в Google Guava.
String converted = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, "FooBar");
assertEquals("fooBar", converted);
Или вы можете подготовить и повторно использовать объект конвертера, который может быть более эффективным.
Converter<String, String> converter=
CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_CAMEL);
assertEquals("fooBar", converter.convert("FooBar"));
Чтобы лучше понять философию манипуляций с строкой Google Guava, ознакомьтесь с этой страницей wiki.
Ответ 9
String testString = "SomeInputString";
String firstLetter = testString.substring(0,1).toLowerCase();
String restLetters = testString.substring(1);
String resultString = firstLetter + restLetters;
Ответ 10
Я пришел к этому только сегодня. Пытался сделать это сам самым пешеходным путем. Это заняло одну строчку, длинную. Здесь идет
String str = "TaxoRank";
System.out.println(" Before str = " + str);
str = str.replaceFirst(str.substring(0,1), str.substring(0,1).toLowerCase());
System.out.println(" After str = " + str);
дает:
До str = TaxoRanks
После str = taxoRanks
Ответ 11
val str = "Hello"
s"${str.head.toLower}${str.tail}"
Результат:
res4: String = hello