如何指定要在子字符串中包含的字母数量(而不是空格数量)?

4
我正在尝试使用索引值打印子字符串。计数时需要排除空格,但输出应与空格一起打印。我想显示主字符串中的n个字母。空格将保持原样,但从下限到上限索引的字母数量应为n。我的代码是:
public class Test {
    public static void main(String args[])
    {
        String Str=new String("Welcome to the class");
        System.out.println("\nReturn value is:");
        System.out.println(Str.substring(2,9));
    }
}

输出: lcome t

在上述代码中,它会计算"Welcome"和"to"之间的空格,我不想计算它们之间的空格。我期望的输出是lcome to


3
注意,几乎不应使用 new String(String)。只需使用 str = "Welcome"; 即可。 - chrylis -cautiouslyoptimistic-
1
为什么需要避免计算空格? - Ephi
1
你想要问什么?请具体说明。谢谢。 - Vikrant Kashyap
5个回答

6

您可以使用简单的数学计算。只需截取字符串,删除所有空格,并将原始长度与没有空格的字符串进行比较。然后将差异大小添加到子字符串的结束索引中。

public static void main(String args[]) {
    String Str = "Welcome to the class";
    System.out.println("\nReturn value is:");
    String sub = Str.substring(2, 9);
    String wsRemoved = sub.replaceAll(" ", "");
    String wsBegginingRemoved = sub.replaceAll("^ *", "");
    String outputSub = Str.substring(2+(sub.length()-wsBegginingRemoved.length()), 9+(sub.length()-wsRemoved.length()+(sub.length() - wsBegginingRemoved.length())));
    System.out.println(outputSub);
}

编辑:不再忽略前导空格

输出

lcome to

输出 "我的名字是Earl"

name is E    

1
@KevinEsche 你很幸运,没有像我一样因为犯了一个简单的错误而被投票踩到底。 - fulvio
1
@majk 这是你的假设。 - fulvio
1
@ majk 除非你知道 OP 想要什么,否则最好不要做任何假设。 - fulvio
1
@ majk 嗯,我提供了一个如何完成的答案,不是100%测试和适合的答案。基于这个答案,OP可以继续他的工作,以达到他想要的结果,也许使用对String中后续空格进行递归检查或其他任何他想要的方法。但这是未知的,因为我们只有一个简单的例子和期望的输出,而这个答案确实生成了它。 - SomeJavaGuy
1
@majk,“return“lcome to”;”怎么成为一个有效的答案?他明确要求对由“Welcome to the class”组成的字符串进行子串操作,并返回“lcome to”。 - fulvio
显示剩余10条评论

4

一个方法是使用正则表达式^.{2}([^ ] *){7}进行提取。

另一种选择是使用简单的for循环遍历字符串,并计算用于子字符串的结束点。

int non_whitespace = 0; int i;
for(i = 2; non_whitespace < 7; ++non_whitespace, ++i) { 
    while (str.charAt(i) == ' ') ++i;
}
return str.substring(2, i);

如果速度是一个问题,你可以考虑哪种方法更易读,并评估哪种方法能够提高性能。


3
你想要做的是从字符串中显示n个字符,包括空格,但n不包括空格数。为此,你可以使用循环而不是库函数。 逻辑:在while循环中保持显示字符串str的索引= 2到索引= 9-1的字符。如果当前字符是空格,则将子字符串的字符串索引的上限n的值增加1,即程序现在会显示超出每个空格遇到的上限一个额外的字符。
请考虑以下代码。
String str = "Welcome to the class";
int index = 2, n = 9;
while(index < n){
    char c = str.charAt(index);
    System.out.print(c);
    if(c==' ')
    n++;
    index++;
}

输出:lcome to
希望您能理解这段代码。


编辑
@Finbarr O'B所说,为了防止程序出现StringIndexOutOfBoundsException,需要进行检查,因此循环必须定义为:

while(index < n && index < str.length()){
    ...
}

3
好的回答,我只想补充一个字符串边界检查,以确保我们不会尝试引用超出字符串长度的部分。 - Finbarr O'B
1
@FinbarrO'Brien 要做到这一点,我们只需要将 while 循环定义为 while(index < n && index < str.length()) 吗? - progyammer
是的,这肯定是一种可能性。当索引超出字符串末尾时,它将完成。 - Finbarr O'B
@progy,我理解了你的代码。相当简单易懂。但我要求一段使用子串的代码。 - Visaali Sundaram
@VisaaliSundaram,我给了你我能想到的最好的答案。不管怎样,很高兴你找到了正确的答案。 - progyammer
@FinbarrO'B 嘿,感谢您指出需要添加字符串边界检查。这对于使该算法健康起来确实非常必要。我也在答案中加入了它。 - progyammer

0

如果您不想使用正则表达式,可以实现自己的版本 substring。直接的解决方案:

private static String substring(int begin, int end, String str) {
    StringBuilder res = new StringBuilder();
    while (begin < end) {
        if (str.charAt(begin) == ' ') {
            end++;
        }
        res.append(str.charAt(begin));
        begin++;
    }
    return res.toString();
}

这里的技巧是忽略空格的“计数”,当遇到空格时增加 end,强制循环进行一次额外的迭代。

代码复杂度为 O(n)。


System.out.println(substring(2, 9, "Welcome to the class"));
>> lcome to

1
从性能角度来看,不使用 StringBuilder 而是使用计算的索引来调用一个子字符串来计算返回值是一个更好的想法。 - majk
1
@majk 我不明白。 - Maroun
1
在开始时,执行 int x = begin;,去掉 StringBuilder 的调用,然后执行 return str.substring(begin, end); - majk
@ majk 我不确定它是否具有更好的性能,因为您正在调用“substring”,这也会进行其他操作。 - Maroun
1
无论如何,我提供了算法,OP可以根据自己的意愿进行更改。 - Maroun

-2
你可以使用 replaceFirst 来实现这个功能:
String Str = "Welcome to the class"; // remove new String()
Str = Str.replaceFirst("^ *", "");
System.out.println("\nReturn value is:");
System.out.println(Str.substring(2, 10)); // increment end index by 1

输出:

欢迎来到


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接