1. Introduction
1.绪论
In this short tutorial, we’ll see several ways to remove leading and trailing characters from a String. For the sake of simplicity, we’ll remove zeroes in the examples.
在这个简短的教程中,我们将看到从字符串中删除前导和尾部字符的几种方法。为了简单起见,我们将在例子中删除零。
With each implementation, we’ll create two methods: one for leading, and one for trailing zeroes.
对于每个实现,我们将创建两个方法:一个用于前导零,一个用于后导零。
This problem has an edge case: what do we want to do, when the input contains zeroes only? Return an empty String, or a String containing a single zero? We’ll see implementations for both use cases in each of the solutions.
这个问题有一个边缘情况:当输入只包含零时,我们要做什么?是返回一个空的String,还是返回一个包含一个零的String?我们将在每个解决方案中看到两种用例的实现。
We have unit tests for each implementation, which you can find on GitHub.
2. Using StringBuilder
2.使用StringBuilder
In our first solution, we’ll create a StringBuilder with the original String, and we’ll delete the unnecessary characters from the beginning or the end:
在我们的第一个解决方案中,我们将用原始的String创建一个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();
}
Note, that we use StringBuilder.setLength() instead of StringBuilder.deleteCharAt() when we remove trailing zeroes because it also deletes the last few characters and it’s more performant.
注意,当我们删除尾部的零时,我们使用StringBuilder.setLength()而不是StringBuilder.deleteCharAt(),因为它也删除了最后几个字符,而且性能更强。
If we don’t want to return an empty String when the input contains only zeroes, the only thing we need to do is to stop the loop if there’s only a single character left.
如果我们不想在输入只包含0时返回一个空的String,我们唯一需要做的就是在只剩下一个字符时停止循环。
Therefore, we change the loop condition:
因此,我们改变循环条件。
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. Using String.subString()
3.使用String.subString()
In this solution when we remove leading or trailing zeroes, we find the position of the first or last non-zero character.
在这个解决方案中,当我们去除前导或尾部的零时,我们找到第一个或最后一个非零字符的位置。
After that, we only have to call substring(), to return the remaining parts:
之后,我们只需要调用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);
}
Note, that we have to declare the variable index before the for loop because we want to use the variable outside the loop’s scope.
注意,我们必须在for循环之前声明变量index,因为我们想在循环的范围之外使用这个变量。
Also note, that we have to look for non-zero characters manually, since String.indexOf() and String.lastIndexOf() work only for exact matching.
还要注意,我们必须手动寻找非零字符,因为String.indexOf()和String.lastIndexOf()只对精确匹配起作用。
If we don’t want to return an empty String, we have to do the same thing like before: change the loop condition:
如果我们不想返回一个空的String,我们必须像以前一样做同样的事情。改变循环条件。
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. Using Apache Commons
4.使用Apache Commons
Apache Commons has many useful classes, including org.apache.commons.lang.StringUtils. To be more precise, this class is in Apache Commons Lang3.
Apache Commons有很多有用的类,包括org.apache.commons.lang.StringUtils。更准确地说,这个类是在Apache Commons Lang3中。
4.1. Dependencies
4.1. 依赖性
We can use Apache Commons Lang3 by inserting this dependency into our pom.xml file:
我们可以使用Apache Commons Lang3,在我们的pom.xml文件中插入这个依赖项。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
4.2. Implementation
4.2.实施
In the StringUtils class, we have the methods stripStart() and stripEnd(). They remove leading and trailing characters respectively.
在StringUtils类中,我们有stripStart()和stripEnd()方法。它们分别去除前导和尾部的字符。
Since it’s exactly what we need, our solution is pretty straightforward:
由于这正是我们所需要的,我们的解决方案是非常直接的。
String removeLeadingZeroes(String s) {
return StringUtils.stripStart(s, "0");
}
String removeTrailingZeroes(String s) {
return StringUtils.stripEnd(s, "0");
}
Unfortunately, we can’t configure, if we want to remove all occurrences or not. Therefore, we need to control it manually.
不幸的是,我们无法配置,是否要删除所有的出现。因此,我们需要手动控制它。
If the input wasn’t empty, but the stripped String is empty, then we have to return exactly one zero:
如果输入不是空的,但剥离后的String是空的,那么我们就必须准确返回一个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;
}
Note, that these methods accept a String as their second parameter. This String represents a set of characters, not a sequence we want to remove.
注意,这些方法接受一个String作为其第二个参数。这个String代表一组字符,而不是我们想要删除的序列。
For example, if we pass “01”, they’ll remove any leading or trailing characters, that are either ‘0′ or ‘1′.
例如,如果我们传递“01”,他们将删除任何前导或尾随字符,这些字符要么是‘0’,要么是‘1’。
5. Using Guava
5.使用番石榴
Guava also provides many utility classes. For this problem, we can use com.google.common.base.CharMatcher, which provides utility methods to interact with matching characters.
Guava也提供了许多实用类。对于这个问题,我们可以使用com.google.common.base.CharMatcher,它提供了与匹配字符交互的实用方法。
5.1. Dependencies
依赖性
To use Guava, we should add the following dependencies to our pom.xml file:
为了使用Guava,我们应该在我们的pom.xml文件中添加以下依赖项。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
Note, that if we want to use Guava in an Android application, we should use version 27.0-android instead.
注意,如果我们想在Android应用程序中使用Guava,我们应该使用27.0-android版本。
5.2. Implementation
5.2.实施
In our case, we’re interested in trimLeadingFrom() and trimTrailingFrom().
在我们的案例中,我们对trimLeadingFrom()和trimTrailingFrom()感兴趣。
As their name suggests, they remove any leading or trailing character respectively from a String, which matches the CharMatcher:
顾名思义,它们分别从String中移除任何前导或尾随的字符,这些字符与CharMatcher匹配。
String removeLeadingZeroes(String s) {
return CharMatcher.is('0').trimLeadingFrom(s);
}
String removeTrailingZeroes(String s) {
return CharMatcher.is('0').trimTrailingFrom(s);
}
They have the same characteristics, as the Apache Commons methods we saw.
它们具有相同的特征,就像我们看到的Apache Commons方法一样。
Therefore, if we don’t want to remove all zeroes, we can use the same trick:
因此,如果我们不想删除所有的零,我们可以使用同样的技巧。
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;
}
Note, that with CharMatcher we can create more complex matching rules.
注意,使用CharMatcher我们可以创建更复杂的匹配规则。
6. Using Regular Expressions
6.使用正则表达式
Since our problem is a pattern matching problem, we can use regular expressions: we want to match all zeroes at the beginning or the end of a String.
由于我们的问题是一个模式匹配问题,我们可以使用正则表达式。我们想匹配一个字符串的开头或结尾的所有零。
On top of that, we want to remove those matching zeroes. In other words, we want to replace them with nothing, or in other words, an empty String.
最重要的是,我们要删除那些匹配的零。换句话说,我们要用什么都没有替换它们,或者换句话说,一个空的String。
We can do exactly that, with the String.replaceAll() method:
我们正是可以通过String.replaceAll()方法做到这一点。
String removeLeadingZeroes(String s) {
return s.replaceAll("^0+", "");
}
String removeTrailingZeroes(String s) {
return s.replaceAll("0+$", "");
}
If we don’t want to remove all zeroes, we could use the same solution we used with Apache Commons and Guava. However, there’s a pure regular expression way to do this: we have to provide a pattern, which doesn’t match the whole String.
如果我们不想删除所有的零,我们可以使用与Apache Commons和Guava相同的解决方案。然而,有一个纯粹的正则表达式的方法:我们必须提供一个模式,它不匹配整个String。
That way, if the input contains only zeroes, the regexp engine will keep exactly one out from the matching. We can do this with the following patterns:
这样一来,如果输入的内容只包含零,regexp引擎就会在匹配中恰好保留一个。我们可以用以下模式来做这件事。
String removeLeadingZeroes(String s) {
return s.replaceAll("^0+(?!$)", "");
}
String removeTrailingZeroes(String s) {
return s.replaceAll("(?!^)0+$", "");
}
Note, that “(?!^)” and “(?!$)” means that it’s not the beginning or the end of the String respectively.
注意,“(?!^)”和“(?!$)”分别意味着它不是字符串的开始或结束。
7. Conclusion
7.结语
In this tutorial, we saw several ways to remove leading and trailing characters from a String. The choice between these implementations is often simply personal preference.
在本教程中,我们看到了从String中移除前导和尾随字符的几种方法。在这些实现中的选择往往只是个人的偏好。
As usual, the examples are available over on GitHub.
像往常一样,这些例子可以在GitHub上找到over。