Перейти к основному содержимому

Удалить начальные и конечные символы из строки

· 6 мин. чтения

1. Введение

В этом коротком руководстве мы увидим несколько способов удаления начальных и конечных символов из String . Для простоты мы удалим нули в примерах.

В каждой реализации мы создадим два метода: один для начальных и один для завершающих нулей.

У этой проблемы есть пограничный случай: что мы хотим делать, когда вход содержит только нули? Вернуть пустую строку или строку , содержащую один ноль? Мы увидим реализации для обоих вариантов использования в каждом из решений.

У нас есть модульные тесты для каждой реализации, которые вы можете найти на GitHub .

2. Использование StringBuilder

В нашем первом решении мы создадим StringBuilder с исходной строкой и удалим ненужные символы в начале или в конце:

String removeLeadingZeroes(String s) {
StringBuilder sb = new StringBuilder(s);
while (sb.length() > 0 && sb.charAt(0) == '0') {
sb.deleteCharAt(0);
}
return sb.toString();
}

String removeTrailingZeroes(String s) {
StringBuilder sb = new StringBuilder(s);
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '0') {
sb.setLength(sb.length() - 1);
}
return sb.toString();
}

Обратите внимание, что мы используем StringBuilder.setLength() вместо StringBuilder.deleteCharAt() , когда удаляем конечные нули, потому что он также удаляет последние несколько символов и более эффективен.

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

Поэтому меняем условие цикла:

String removeLeadingZeroes(String s) {
StringBuilder sb = new StringBuilder(s);
while (sb.length() > 1 && sb.charAt(0) == '0') {
sb.deleteCharAt(0);
}
return sb.toString();
}

String removeTrailingZeroes(String s) {
StringBuilder sb = new StringBuilder(s);
while (sb.length() > 1 && sb.charAt(sb.length() - 1) == '0') {
sb.setLength(sb.length() - 1);
}
return sb.toString();
}

3. Использование String.subString()

В этом решении, когда мы удаляем начальные или конечные нули, мы находим позицию первого или последнего ненулевого символа.

После этого нам нужно только вызвать substring() , чтобы вернуть оставшиеся части:

String removeLeadingZeroes(String s) {
int index;
for (index = 0; index < s.length(); index++) {
if (s.charAt(index) != '0') {
break;
}
}
return s.substring(index);
}

String removeTrailingZeroes(String s) {
int index;
for (index = s.length() - 1; index >= 0; index--) {
if (s.charAt(index) != '0') {
break;
}
}
return s.substring(0, index + 1);
}

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

Также обратите внимание, что нам нужно искать ненулевые символы вручную, так как String.indexOf() и String.lastIndexOf() работают только для точного совпадения.

Если мы не хотим возвращать пустую строку , мы должны сделать то же самое, что и раньше: изменить условие цикла :

String removeLeadingZeroes(String s) {
int index;
for (index = 0; index < s.length() - 1; index++) {
if (s.charAt(index) != '0') {
break;
}
}
return s.substring(index);
}

String removeTrailingZeroes(String s) {
int index;
for (index = s.length() - 1; index > 0; index--) {
if (s.charAt(index) != '0') {
break;
}
}
return s.substring(0, index + 1);
}

4. Использование Apache Commons

В Apache Commons есть много полезных классов, в том числе org.apache.commons.lang.StringUtils . Если быть точнее, этот класс есть в Apache Commons Lang3.

4.1. Зависимости

Мы можем использовать Apache Commons Lang3 , вставив эту зависимость в наш файл pom.xml :

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>

4.2. Реализация

В классе StringUtils у нас есть методы stripStart() и stripEnd() . Они удаляют начальные и конечные символы соответственно.

Поскольку это именно то, что нам нужно, наше решение довольно простое:

String removeLeadingZeroes(String s) {
return StringUtils.stripStart(s, "0");
}

String removeTrailingZeroes(String s) {
return StringUtils.stripEnd(s, "0");
}

К сожалению, мы не можем настроить, хотим мы удалить все вхождения или нет. Поэтому нам нужно управлять им вручную.

Если ввод не был пустым, но очищенная строка пуста, то мы должны вернуть ровно один ноль:

String removeLeadingZeroes(String s) {
String stripped = StringUtils.stripStart(s, "0");
if (stripped.isEmpty() && !s.isEmpty()) {
return "0";
}
return stripped;
}

String removeTrailingZeroes(String s) {
String stripped = StringUtils.stripEnd(s, "0");
if (stripped.isEmpty() && !s.isEmpty()) {
return "0";
}
return stripped;
}

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

Например, если мы передаем «01» , они удалят все начальные или конечные символы, такие как «0» или «1» .

5. Использование гуавы

Guava также предоставляет множество служебных классов. Для этой проблемы мы можем использовать com.google.common.base.CharMatcher , который предоставляет служебные методы для взаимодействия с соответствующими символами.

5.1. Зависимости

Чтобы использовать Guava, мы должны добавить следующие зависимости в наш файл pom.xml :

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>

Обратите внимание: если мы хотим использовать Guava в приложении для Android, вместо этого мы должны использовать версию 27.0-android .

5.2. Реализация

В нашем случае нас интересуют функции trimLeadingFrom() и trimTrailingFrom() .

Как следует из их названия, они удаляют любой начальный или конечный символ соответственно из String , который соответствует CharMatcher :

String removeLeadingZeroes(String s) {
return CharMatcher.is('0').trimLeadingFrom(s);
}

String removeTrailingZeroes(String s) {
return CharMatcher.is('0').trimTrailingFrom(s);
}

У них те же характеристики, что и у методов Apache Commons, которые мы видели.

Поэтому, если мы не хотим удалять все нули, мы можем использовать тот же трюк:

String removeLeadingZeroes(String s) {
String stripped = CharMatcher.is('0').trimLeadingFrom(s);
if (stripped.isEmpty() && !s.isEmpty()) {
return "0";
}
return stripped;
}

String removeTrailingZeroes(String s) {
String stripped = CharMatcher.is('0').trimTrailingFrom(s);
if (stripped.isEmpty() && !s.isEmpty()) {
return "0";
}
return stripped;
}

Обратите внимание, что с помощью CharMatcher мы можем создавать более сложные правила сопоставления.

6. Использование регулярных выражений

Поскольку наша проблема связана с сопоставлением с образцом, мы можем использовать регулярные выражения: мы хотим сопоставить все нули в начале или в конце строки . ``

Кроме того, мы хотим удалить эти совпадающие нули. Другими словами, мы хотим заменить их ничем, или, другими словами, пустой строкой .

Мы можем сделать именно это с помощью метода String.replaceAll() :

String removeLeadingZeroes(String s) {
return s.replaceAll("^0+", "");
}

String removeTrailingZeroes(String s) {
return s.replaceAll("0+$", "");
}

Если мы не хотим удалять все нули, мы можем использовать то же решение, которое мы использовали с Apache Commons и Guava. Однако есть способ сделать это с помощью регулярных выражений: мы должны предоставить шаблон, который не соответствует всей String .

Таким образом, если входные данные содержат только нули, механизм регулярных выражений не допустит сопоставления ровно один. Мы можем сделать это с помощью следующих шаблонов:

String removeLeadingZeroes(String s) {
return s.replaceAll("^0+(?!$)", "");
}

String removeTrailingZeroes(String s) {
return s.replaceAll("(?!^)0+$", "");
}

Обратите внимание, что «(?!^)» и «(?!$)» означают, что это не начало или конец строки соответственно.

7. Заключение

В этом руководстве мы увидели несколько способов удаления начальных и конечных символов из String . Выбор между этими реализациями часто является просто личным предпочтением.

Как обычно, примеры доступны на GitHub .