2011-04-12 41 views
2

下面的代码来自于我的教科书中的一个赋值,用于输入用户输入名称并大写首字母和姓的第一个字母的简单程序。该代码正常工作,但我不明白为什么name.substring()正常工作。具体来说,我感兴趣的是第24-29行的区块是如何工作的。如果用户输入名称“Johnny Johnson”,则i应该包含进入第29行的值7。如果i确实包含7,则不应该包含“Johnny J”,其应该使得第29行实际存储“JohnnyJJohnson”在String name?但实际上它应该存储“约翰尼约翰逊”。有关String.substring(int,int)如何工作的帮助

我的第二个问题来自这个代码搞乱看到不同的结果。如果我改变线29的第一部分name = name.substring(0, i-1)我得到(使用Eclipse)的错误:在线程

异常“主” java.lang.StringIndexOutOfBoundsException: 字符串索引超出范围:在java的15 .lang.String.charAt(String.java:558) 在 RepairName.main(RepairName.java:17)

为什么在第17行,而不是第29行出现错误?其实,为什么我会得到一个错误,因为i-1实际上并没有改变i的值是否正确?我认为它与循环有关,但由于i的值没有改变,所以我不知道它为什么会这样。

对不起,这是一个冗长的问题。我对Java很陌生,对编程也很新颖(显然),但是我很欣赏你们所有人都能提供的见解。谢谢!

1 import javax.swing.*; 
2 
3 public class RepairName 
4 { 
5 public static void main(String[] args) 
6 { 
7  String name, saveOriginalName; 
8   int stringLength; 
9   int i; 
10   char c; 
11   name = JOptionPane.showInputDialog(null, "Please enter your first and last name"); 
12  
13   saveOriginalName = name; 
14   stringLength = name.length(); 
15   for (i = 0; i < stringLength; i++) 
16   { 
17     c = name.charAt(i); 
18     if (i == 0) 
19     { 
20       c = Character.toUpperCase(c); 
21       name = c + name.substring(1, stringLength); 
22     } 
23     else 
24      if(name.charAt(i) == ' ') 
25       { 
26        i++; 
27         c = name.charAt(i); 
28         c = Character.toUpperCase(c); 
29         name = name.substring(0, i) + c + name.substring(i+1, stringLength); 
30       } 
31   } 
32   JOptionPane.showMessageDialog(null, "Original name was " + saveOriginalName + "\nRepaired name is " + name); 
33 } 
34 
35 } 

回答

3

String.subString(int, int)的javadoc:

public String substring(int beginIndex, int endIndex) 

返回一个新字符串,它是此字符串的一个子 。子字符串 子字符串从指定的 beginIndex开始,并在索引endIndex - 1处扩展到 字符。因此 子字符串的长度为 endIndex-beginIndex。

继承人的链接:http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#substring(int,INT)

如有疑问看的javadoc:d

关于你的第二quesstion,再次的Javadoc(http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#charAt(int))为charAt(int)为您排忧解难:

抛出:IndexOutOfBoundsException - 如果 索引参数大于该STRI的长度负或不 更少NG。

如果你在你的子串由1每次找到一个' '时间递减名的大小使用i-1。这意味着它将迭代15次,但在找到' '之后,name将只有14个字符长。

+0

非常感谢您的解释!我甚至没有想到循环的第一次迭代......我只是想着最后一个。我有很多东西需要学习。感谢您的链接 – knobcreekman 2011-04-12 21:55:28

+0

小调:我们现在有1.6(但是子串当然没有改变)。 – 2011-04-12 21:56:14

+0

真的,大声笑我刚刚搜索了Java字符串API,并得到了第一击:D – Tnem 2011-04-12 21:57:22

1

引述substring的Javadoc,

的串开始在指定的beginIndex和延伸到字符索引endIndex - 1的

换句话说,endIndex是不包括在结果中。

至于你的第二个问题,它与你有关,减少循环内的name的长度。你的循环条件(i < stringLength)和你看看name.charAt(i)的事实假定name的长度保持不变(或最小不减少)。当你开始缩短字符串的时候,这会受到侵犯。

+0

非常感谢解释! – knobcreekman 2011-04-12 21:56:06

1

这是正确的子工程是这样的:

public String substring(int beginIndex, int endIndex) 

返回一个新字符串,它是此字符串的一个子 。子字符串 子字符串从指定的 beginIndex开始,并在索引endIndex - 1处扩展到 字符。因此 子字符串的长度为 endIndex-beginIndex。

所以子(0,7),它需要0..6个字符的字符串从


注意,这是非常糟糕的做法,修改for循环(我++里面换迭代的价值循环体)。如果在空间之后你没有任何其他字符,你会遇到异常

+0

我感谢您的帮助! – knobcreekman 2011-04-12 21:56:52

1

嗨你得到的异常,因为你遍历字符串,但在for循环中,你实际上正在改变字符串length name = name.substring(0 ,i)+ c + name.substring(i + 1,stringLength); 所以,当你仍然在循环中,名称的大小不再等于旧的stringLength。

米堡

1
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 15 at java.lang.String.charAt(String.java:558) at RepairName.main(RepairName.java:17) 

发生,因为你是第21行和29改变name和保持的name相同的长度stringLength

1

广告1)的javadoc,是一个很好的参考,下面的java .lang.String.substring(...):

public String substring(int beginIndex, int endIndex) 

返回一个新字符串,该字符串是此字符串的子字符串。子字符串 子字符串从指定的 beginIndex开始,并在索引endIndex - 1处扩展到 字符。因此 子字符串的长度为 endIndex-beginIndex。

的好处,在排除年底的指数,是,你可以sequently遍历值:

a [0] = x.substring (0, 5); 
a [1] = x.substring (5, 10); 
a [2] = x.substring (10, 15); 

// or 

a [i] = x.substring (i*5, (i+1)*5); 
+0

感谢您的帮助!第二部分有点超过我的头虽然*尴尬* – knobcreekman 2011-04-12 21:59:14

+0

一个序列(5,10,...)的结尾可以是下一个序列的开始(...,5,10)。另一个好处是,您可以使用String.length作为不带-1的结束索引。不是很重要,只是方便。 – 2011-04-13 00:37:58

+0

好吧,我现在明白了。再次感谢 – knobcreekman 2011-04-13 01:04:18

1

广告2)

你不改变我自己,但name在这里被截断:

name = name.substring(0,i-1)+ c + name.substring(i + 1,stringLength);

但外环没有通知新的长度。

广告3)(代码审查):

还应当声明并尽可能晚地初始化变量,并标记尽可能决赛。这告诉你,在初始化之后,你不必担心它们。

鉴于此代码:

import javax.swing.*; 

public class RepairName 
{ 
    public static void main(String[] args) 
    { 
     final String name = JOptionPane.showInputDialog(null, "Please enter your first and last name"); 
     final String saveOriginalName = name; 
     final int stringLength = name.length(); 
     System.out.println (name); 
     for (int i = 0; i < stringLength; i++) 
     { 
       final char c = name.charAt (i); 
       if (i == 0) 
       { 
         char upper = Character.toUpperCase (c); 
         name = upper + name.substring (1, stringLength); 
       } 
       else 
        if (c == ' ') 
         { 
          i++; 
           final char c2 = name.charAt (i); 
           final char upper = Character.toUpperCase (c2); 
           name = name.substring (0, i-1) + upper + name.substring (i+1, stringLength); 
         } 
     } 
     JOptionPane.showMessageDialog (null, "Original name was " + saveOriginalName + "\nRepaired name is " + name); 
    } 
} 

你会得到一个错误信息,对于名称为决赛。也许这会阻止你意外地与长度不同步。

修改,有一个可变的UPNAME,但遍历名称:

String upName = null; 
    for (int i = 0; i < stringLength; i++) 
    { 
      final char c = name.charAt (i); 
      if (i == 0) 
      { 
        char upper = Character.toUpperCase (c); 
        upName = upper + name.substring (1, stringLength); 
      } 
      else 
       if (c == ' ') 
        { 
         i++; 
          final char c2 = name.charAt (i); 
          final char upper = Character.toUpperCase (c2); 
          upName = upName.substring (0, i-1) + upper + name.substring (i+1, stringLength); 
        } 
    } 
    JOptionPane.showMessageDialog (null, "Original name was " + saveOriginalName + "\nRepaired name is " + upName); 

给你,输入“HONKY tonky”输出“HonkyTonky”,这将导致你的方式,子(从,到)的作品,也许。 :)