I have a string, which I want to iterate through and remove every 8th char. I have been trying with an modulo operation which check if i % 8 == 0. However, since I remove every 8th char the length of the string decreases, and I am therefore unable to perform that operation.
StringBuilder str = "1100110001011011000000000000000000000000000000000000000000000000";
System.out.println(str + " " + str.length());
for (int i = 0; i < str.length(); i++) {
// Every 8th element should be discarded
if (i > 7 && i % 8 == 0) {
str.deleteCharAt(i);
}
}
System.out.println(str + " " + str.length());
The length of the string is in the beginning 64, and after the for loop 57, which should be 56.
The main problem with your code is that you don't adjust i when removing characters.
Let's visualize that. You want to remove the following marked characters ("every 8th element"):
1100110001011011000000000000000000000000000000000000000000000000
^ ^ ^ ^ ^ ^ ^ ^
Now we're at i = 7 and remove that character, but because you don't adjust i accordingly the markers keep the same:
110011001011011000000000000000000000000000000000000000000000000
^ ^ ^ ^ ^ ^ ^ ^
Let's do that for 1 = 15 to i = 55:
11001100101101100000000000000000000000000000000000000000000000 //i = 15
1100110010110110000000000000000000000000000000000000000000000 //i = 23
110011001011011000000000000000000000000000000000000000000000 //i = 31
11001100101101100000000000000000000000000000000000000000000 //i = 39
1100110010110110000000000000000000000000000000000000000000 //i = 47
110011001011011000000000000000000000000000000000000000000 //i = 55
^ ^ ^ ^ ^ ^ ^ ^
As you can see, all but the last marker point to a valid character but you won't reach i = 63 because after the first time you remove a character there only are 63 left in the string and thus a max index of 62.
That's why your resulting string has 57 instead of 56 characters, the last "remove" operation doesn't run (and the others except the first remove the wrong elements).
To fix that iterate backwards, i.e. from i = str.length() - 1 to i = 0. Then you can remove every element where (i + 1) % 8 == 0.
Alternatively, as I said in my comment, use a regex: String shortened = str.replaceAll( "(.{7}).", "$1" );
This will match any sequence of 7 characters followed by another (8th) character and replaces that with the first group of 7 (thus skipping the 8th).
There is not deleteCharAt method in String, so I suppose you meant StringBuilder?
You can just reverse the direction of the for loop, so that it starts from the end of the string:
String str = "11111111811111118";
StringBuilder builder = new StringBuilder(str);
System.out.println(str + " " + str.length());
for (int i = str.length() - 1; i >= 0; i--) {
// Every 8th element should be discarded
if (i > 7 && i % 8 == 0) {
builder.deleteCharAt(i);
}
}
System.out.println(builder+ " " + builder.length());
By deleting chars from the end of the string, the indices of the chars to be removed no longer changes as you move along the string.
Why don't you use regex and achieve it in two lines of code like this,
public static void main(String[] args) {
String str = "1100110001011011000000000000000000000000000000000000000000000000";
String replacedStr = str.replaceAll("([01]{7})[01]", "$1");
System.out.println(str.toString() + " " + str.length());
System.out.println(replacedStr.toString() + " " + replacedStr.length());
}
This gives perfectly correct output,
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
Alternatively, you can follow this traditional solution like you attempted.
Strings in java are immutable. So instead you should create a StringBuilder object and keep copying every character, except 8th character.
For correctly counting every 8th character, initialize your for loop index run from 1 rather than 0, like in this code, which will eradicate every 8th character effectively where you wanted to do if (i%8==0)
public static void main(String[] args) {
String str = "1100110001011011000000000000000000000000000000000000000000000000";
StringBuilder sb = new StringBuilder();
System.out.println(str + " " + str.length());
for (int i = 1; i <= str.length(); i++) {
// Every 8th element should be discarded
if (i % 8 == 0) {
// str.deleteCharAt(i);
} else {
sb.append(str.charAt(i-1));
}
}
System.out.println(sb.toString() + " " + sb.length());
}
And this gives following output,
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
You can verify here where only every 8th character is gone in this output.
The problem is that Strings are starting with 0. Therefore the 8th element has the index 7 and has to be removed as well, which you don't do in your loop. I'd write it like that (but noting that this might not be the most elegant solution):
public static void main(String[] args)
{
String str = "1100110001011011000000000000000000000000000000000000000000000000";
System.out.println(str + " " + str.length());
int idx = 0;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
idx++;
if (idx == 8) {
idx = 0;
continue;
}
sb.append(str.charAt(i));
}
System.out.println(sb.toString() + " " + sb.length());
}
Outputs:
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
Assuming that the string does not contain the char with ASCII value 0, convert the string to a char array and change every 8th char with the char with ASCII value 0, then reconstruct the string and replace all chars with ASCII value 0 with "":
String str = "0123456701234567012345670123456701234567012345670123456701234567";
System.out.println("initial = " + str);
char[] array = str.toCharArray();
for (int i = 7; i < array.length; i = i + 8) {
array[i] = 0;
}
str = String.valueOf(array).replace(String.valueOf(Character.toChars(0)), "");
System.out.println("final = " + str);
will print:
initial = 0123456701234567012345670123456701234567012345670123456701234567
final = 01234560123456012345601234560123456012345601234560123456
An alternative way is using substring() method.
substring(int beginIndex, int endIndex) Returns a new string that is a
substring of this string.
In every turn add 7 chars of the string to the new string and skip the 8th element of the string: sb.append(str.substring(start, start+7));
In first turn:
str.substring(0, 7) -> "1100110"
start += 8; -> start = 8;
In second turn:
str.substring(8, 15) -> "0101101"
start += 8; -> start = 23;
...
So the 8th element/the element has the index 7 ("0") has been skipped.
String str = "1100110001011011000000000000000000000000000000000000000000000000";
int length = str.length();
int start = 0;
StringBuilder sb = new StringBuilder();
while((start+7)<length) {
sb.append(str.substring(start, start+7));
start += 8;
}
if(start<length) {
sb.append(str.substring(start, length));
}
System.out.println(sb + " " + sb.length());
System.out.println(str + " " + str.length());
Output:
11001100101101000000000000000000000000000000000000000000 56
1100110001011011000000000000000000000000000000000000000000000000 64
String doesn't have a deleteCharAt() method. If it did, it would return the update string, since String is immutablem so code would have had to be str = str.deleteCharAt(i);.
You could use StringBuilder instead, since it does have a deleteCharAt() method.
To delete every 8th character, start at the end. That way index values are unaffected by already deleted characters, which is your current problem.
String str = "1100110001011011000000000000000000000000000000000000000000000000";
System.out.println(str + " " + str.length());
StringBuilder buf = new StringBuilder(str);
for (int i = (buf.length() - 1) / 8 * 8; i >= 0; i -= 8)
buf.deleteCharAt(i);
str = buf.toString();
System.out.println(str + " " + str.length());
Output
1100110001011011000000000000000000000000000000000000000000000000 64
10011001011011000000000000000000000000000000000000000000 56
UPDATE
The above code deletes the 1st, 9th, 17th, ... character, i.e. characters at index 0, 8, 16, ..., which is in accordance with "remove every 8th char" and "check if i % 8 == 0" mentioned in the question.
If code should delete the 8th, 16th, 24th, ... character, i.e. characters at index 7, 15, 23, ..., then change initialization of i as follows:
for (int i = (buf.length() - 8) & ~7 | 7; i >= 0; i -= 8)
buf.deleteCharAt(i);
Output
1100110001011011000000000000000000000000000000000000000000000000 64
11001100101101000000000000000000000000000000000000000000 56
Since StringBuilder::deleteCharAt changes the size of the underlying sequence, you need to process the target string in reverse order.
This solution is based on streams.
// create target string
String s = Stream.generate(() -> IntStream.range(0, 10))
.limit(10)
.map(stream -> stream.mapToObj(Objects::toString).collect(Collectors.joining()))
.collect(Collectors.joining());
StringBuilder sb = new StringBuilder(s);
// delete first element or not?
boolean removeFirst = false;
IntStream.range(removeFirst ? 0 : 1, s.length())
.boxed()
.sorted(Collections.reverseOrder()) // reverse number stream
.filter(i -> i % 8 == 0) // only keep multiples of 8
.forEach(sb::deleteCharAt);
System.out.println(s);
System.out.println(sb.toString());
This is the output it produces
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
123456790123457890123567890134567891234567901234578901235678901345678912345679012345789
The first element missing is the 8, then 6 (16), then the 4 (24), etc.
Related
I write a func of Caesar Cipher.
So after I shift a sentence, I want also shift back to the original sentence.
For now it works only for one direction, when I shift with natural positive number, but when I try to do this with negative number, it goes on to value less than 97 of ascii lowercase letters.
I give an example:
word: java
key = 10
output: tkfk
Now I want to shift back, to restore my word from tkfk to java.
key = -10
output: ja\a
Instead of v it put \
I know its happens couse from f to minus 10 from ascii table is the letter '\' and I want the letter v.
I think I need to manipulate this line, but I dont know how, I'm a little bit stuck and I don't have an idea what to do.
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97)
My method: (little bit long)
public static void MakeCipherText(String[] text, int key) {
int index =0;
if (key > 0) {
if( text[index] == null || text[index].equals("")) {
System.out.println("No sentences to fix capital letters.");
} else {
while(text[index] != null && !text[index].equals("")) { // only if we have sentence in array or array not contain empty sentence we go through loop
String chiPstr = "";
for(int i=0; i<text[index].length(); i++) {//we work in every itration on 1 sentence (1 index of str array)
if(Character.isLowerCase(text[index].charAt(i))) {//if we have lower letter than:
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97); //we put asci value + Cipher value
chiPstr = chiPstr + ch; //each time we add to the new sentece the result
} else if(Character.isUpperCase(text[index].charAt(i))) {//same thing like here, but its work on uppercase letters.
char ch = (char) (((int) text[index].charAt(i) + key-65) % 26+65);
chiPstr = chiPstr + ch;
}else {// if we have space, or other characters that is no a letter, we just put him as is in a sentence.
chiPstr = chiPstr + text[index].charAt(i);
}
}
text[index] = chiPstr;
index ++;
}
}
} else { // key is negetive number
if( text[index] == null || text[index].equals("")) {
System.out.println("No sentences to fix capital letters.");
} else {
while(text[index] != null && !text[index].equals("")) { // only if we have sentence in array or array not contain empty sentence we go through loop
String chiPstr = "";
for(int i=0; i<text[index].length(); i++) {//we work in evry itration on 1 sentence (1 index of str array)
if(Character.isLowerCase(text[index].charAt(i))) {//if we have lower letter than:
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97); //we put asci value + Cipher value
chiPstr = chiPstr + ch; //each time we add to the new sentece the result
} else if(Character.isUpperCase(text[index].charAt(i))) {//same thing like here, but its work on uppercase letters.
char ch = (char) (((int) text[index].charAt(i) + key-65) % 26+65);
chiPstr = chiPstr + ch;
}else {// if we have space, or other characters that is no a letter, we just put him as is in a sentence.
chiPstr = chiPstr + text[index].charAt(i);
}
}
text[index] = chiPstr;
index ++;
}
}
}
}
Any suggestion?
As the comments suggest you should really check your code again this will also help you to be a better programmer. But anyway you think too complicated.
If you check your else part that is the exact copy of the if part. And that is no wonder. To decode Caesar cipher you encode it basically again with the right key to encode.
For example:
If you encode it with A => B or in this example with 1:
test--> uftu
so how can we decode uftu back?
When we shift it with B=>A or in this case with 25.
uftu --> test
So in your requirement you want if you put -1 that you decode text that was encoded with 1 before.
So basically we have to find a method to map -1 to 25, -2 to 24 and so on.
And the key function is: modulo
-2 % 26 => 24
-1 % 26 => 25
...
In addition you can even now put numbers bigger than 26 because:
500 % 26 => 6
-500 % 26 => 20
and because 2 % 26 => 2 you don't even need that if clause. Your code looks like this in the end:
public static void MakeCipherText(String[] text, int key) {
int index =0;
key = (((key % 26) + 26) % 26); // See below for explanation of this weird modulo
if( text[index] == null || text[index].equals("")) {
System.out.println("No sentences to fix capital letters.");
} else {
while(text[index] != null && !text[index].equals("")) { // only if we have sentence in array or array not contain empty sentence we go through loop
String chiPstr = "";
for(int i=0; i<text[index].length(); i++) {//we work in every itration on 1 sentence (1 index of str array)
if(Character.isLowerCase(text[index].charAt(i))) {//if we have lower letter than:
char ch = (char) (((int) text[index].charAt(i) + key-97) % 26+97); //we put asci value + Cipher value
chiPstr = chiPstr + ch; //each time we add to the new sentece the result
} else if(Character.isUpperCase(text[index].charAt(i))) {//same thing like here, but its work on uppercase letters.
char ch = (char) (((int) text[index].charAt(i) + key-65) % 26+65);
chiPstr = chiPstr + ch;
}else {// if we have space, or other characters that is no a letter, we just put him as is in a sentence.
chiPstr = chiPstr + text[index].charAt(i);
}
}
text[index] = chiPstr;
index ++;
}
}
}
Never forget to use functions and don't use duplicate code. Bad style and error prone. The solution is quite easy if you think it through.
Information weird modulo function
You see I use a weird modulo function. Because in Java % don't calculate the modulo but the remainder. (Different then in Python).
So to get the "true" modulo in Java we have to use this weird trick:
Reference: What's the difference between “mod” and “remainder”?
key = (((key % 26) + 26) % 26);
I wrote a program that sums the int values in a String. I'm getting the wrong output though. I can't quite figure out the issue. The expected output should be 23 and 29 but I am getting 263 and 269. Any suggestions would be helpful; it seems it is putting a 6 between my outputs for some reason.
public class ParseString
{
String str;
public ParseString(String x)
{
this.str = x;
}
public int sumOfAllDigits()
{
int total = 0;
char[] arr = new char[this.str.length()];
for(int i = 0; i < this.str.length(); i++)
{
arr[i] = this.str.charAt(i);
}
for(int i = 0; i < arr.length; i++)
{
if(arr[i] >= '0' && arr[i] <= '9')
{
total = total + arr[i];
}
}
return total;
}
public class TestParseString
{
public static void main(String[] args)
{
String s1 = "AB458JK2L#4";
ParseString ps1 = new ParseString(s1);
System.out.println("Sum of all digits in \"" + s1 + "\" is: ");
System.out.println(ps1.sumOfAllDigits());
System.out.println();
String s2 = "8927KL3PY";
ParseString ps2 = new ParseString(s2);
System.out.println("Sum of all digits in \"" + s2 + "\" is: ");
System.out.println(ps2.sumOfAllDigits());
}
}
It's not that a 6 is inserted into your sum; it's that your sum is 240 too high. There are 5 digits in each of your test strings. What is missing here is what goes on in the conversion between char and int. A '0' is not 0; when a char is widened to an int for summing, it takes the ASCII value, which for numbers is the represented number plus 48. E.g. '0' -> 48, '1' -> 49, etc.
An extra 48 added 5 times yields an extra 240.
Because the digits are coded in order starting with '0' at 48, you can subtract '0' to take away the unwanted 48.
total = total + arr[i] - '0';
As an aside, as already mentioned in the comments on the question, toCharArray() gets you the char[] for a String more easily than manually copying each character.
The problem lies here:
total = total + arr[i];
arr[i] is a char. When you use the + operator on it, with the other operand being an int, you are actually adding the ASCII value of the character, which is 48 to 57 for 0 to 9.
You think you are doing this:
4 + 5 + 8 + 2 + 4
But actually the program is doing:
52 + 53 + 56 + 50 + 52
So that's why you get such a large number.
You need to parse the characters to get the correct output. One way to do this is to just subtract 48!
total = total + (arr[i] - 48);
Or you can convert it to a string first, then parse it as an int:
total = total + Integer.parseInt(Character.toString(arr[i]));
I am trying to wrap text based on a width of 10 characters. After looking at other questions, I have the following:
StringBuilder sb = new StringBuilder(s);
int i = 0;
while (i + 10 < sb.length() && (i = sb.lastIndexOf(" ", i + 10)) != -1) {
sb.replace(i, i + 1, "\n");
}
System.out.println(sb.toString());
This works until a word in my string is longer than the specified width. When this occurs, the rest of the string is printed on line line instead of still following the line width rule. Any ideas? I tried an "else" with a separate condition but I couldn't get it to work. Apologies if this seems rather trivial.
There is a ready solution for that.
https://mvnrepository.com/artifact/org.apache.commons/commons-text
WordUtils.wrap(s, 10);
When you have a word that's longer than 9 characters, sb.lastIndexOf("", i + 10) gives you -1. That's because index of the next space is greater than i + 10 and sb.lastIndexOf("", i + 10) starts from index i + 10 and looks for a space until the beginning of the string and cannot find any spaces (they have all been replaced with new lines). You can fix your code like below to make it work.
StringBuilder sb = new StringBuilder(s);
int i = 0;
while (i + 10 < sb.length() &&
(i = Math.max( sb.indexOf(" ", i), sb.lastIndexOf(" ", i + 10))) != -1) {
sb.replace(i, i + 1, "\n");
}
System.out.println(sb.toString());
You could convert your string to an array of characters and visit them and ask if the variable iterator % 10 (in this case in 9 because i = 0), if so You enter a line break plus the character, all this will be added to a StringBuilder ... might be a solution
char[] a="ABCDFGHIKLMNOPQRSTUVWXYZ".toCharArray(); //String convert to charArray
StringBuilder sb = new StringBuilder(a.length);
for (int i = 0; i < a.length; i++) {
if(i%9==0) sb.append("\n" + a[i]); //
sb.append(a[i]);
}
System.out.println(sb.toString());
My situation: I have a string (called str). The length of the string must be a multiple of 30 (e.g 30, 60, 90). If the length of the str is not a multiple of 30, add spaces " " to the end of it.
Something like this:
if (str.length() / 30 != ????) {
//add spaces to the end
}
Of course, the code above is not correct. It would be very appreciated if you could help me with this.
Thanks in advance!
You can quite simply do:
if(str.length()%30!=0)
str = String.format("%1$-"+(((str.length()/30)*30)+30)+"s", str);
str.length()%30 gives the remainder on dividing the length by 30. If it is not 0, then you have to add spaces.
String.format("%1$-"+(((str.length()/30)*30)+30)+"s", str) adds the spaces to the right of the String.
Or even simply, you can do:
while(str.length()%30 !=0)
str+= ' ';
this code is not tested but i guess it will work:
int a = str.length()%30;
for(int i=0; i<=a; i++)
str = str + " ";
What would you do to check if a number is a multiple of 30 in simple Maths?
Yes, you would divide and check if the remainder is 0 or not, right?
That's how you'll do it in Java. To get the remainder in Java, Modulus(%) operator is used. So, you can do it like this :
if (str.length() % 30 != 0) {
//add spaces to the end
str += " ";
}
or if you want to add spaces to make the length a multiple of 30, then do this:
int remainder = str.length() % 30;
if (remainder != 0) {
//add spaces to the end
int numSpacesRequired = 30-remainder; //no. of spaces reuired to make the length a multiple of 30
for(int i = 0; i < numSpacesRequired; i++)
str += " ";
}
Read more about the basic operators in Java here.
You can use Modulo to achieve that:
if (str.length() % 30 != 0) {
//add spaces to the end
str += ' ';
}
Simply: (Tested and worked)
public static void main(String[] args) {
String str = "AYOA"; //Length is only 4
//If the remainder of the str's length is not 0 (Not a multiple)
if (str.length() % 30 != 0){
str += ' ';
}
System.out.println("[" + str + "]"); //A space is added at the back
}
If you want to add the space continuously until the length is a multiple of 30:
public static void main(String[] args) {
String str = "AYOA"; //Length is only 4
//If the remainder of the str's length is not 0 (Not a multiple)
//Repeat until is multiple of 30
while(str.length % 30 != 0){
str += ' ';
}
System.out.println("[" + str + "]"); //A space is added at the back
}
use StringBuilder to build whitespaces
String str="multiple of 30";
int spacesNum=str.length()%30; //get the remainder
StringBuilder spaces=new StringBuilder(); //build white spaces
for(int j=0;j<spacesNum;j++){
spaces.append(' ');
}
System.out.println(str+spaces.toString());
the code below is from an assignment in my text book for a simple program that takes a user's entered name and capitalizes the first letter of the first and last name. The code works properly, but I do not understand why the name.substring() works correctly. Specifically, I am interested in how the block from lines 24 - 29 works. If the user enters the name "Johnny Johnson", then i should contain the value 7 going into line 29. If i does contain 7, then shouldn't name = name.substring(0, i) contain "Johnny J" which should make line 29 actually store "Johnny JJohnson" in String name? But instead it actually stores "Johnny Johnson" as it should.
My second question comes from messing around with this code to see different results. If I change the first part of line 29 to name = name.substring(0, i-1) I get the error (using Eclipse):
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)
Why does the error appear on line 17 instead of line 29? Actually, why do I get an error at all because i-1 isn't actually changing the value of i correct? I assumed it had something to do with the loop but since the value of i wasn't changed I didn't know why it would.
Sorry if this was a long-winded question. I'm new to Java and pretty new to programming (obviously), but I appreciate any insight you all can give. Thanks!
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 }
From the String.subString(int, int) javadoc:
public String substring(int beginIndex, int endIndex)
Returns a new string that is a
substring of this string. The
substring begins at the specified
beginIndex and extends to the
character at index endIndex - 1. Thus
the length of the substring is
endIndex-beginIndex.
Heres the link: http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#substring(int, int)
If in doubt look at the javadocs :D
As for your second quesstion, again the javadocs ( http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#charAt(int) ) for charAt(int) help you out:
Throws: IndexOutOfBoundsException - if
the index argument is negative or not
less than the length of this string.
If you use i-1 in substring you are decreasing the size of name by 1 each time it finds a ' '. This means it will iterate 15 times, but the name will only be 14 characters long after the ' ' is found.
To quote the substring Javadoc,
The substring begins at the specified beginIndex and extends to the character at index endIndex - 1.
In other words, endIndex is not included in the result.
As to your second question, it has to do with you reducing the length of name inside the loop. Your loop condition (i < stringLength) and the fact that you look at name.charAt(i) assume that the length of name remains constant (or least does not decrease). This gets violated the moment you start shortening the string.
Hi You get the Exception because you iteratate over the string but in the for loop you are actually changing the strings length name = name.substring(0, i) + c + name.substring(i+1, stringLength);
So while you are still in the loop the size of the name is no longer equal to the old stringLength.
Boro
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)
Occurs because you are altering name on line 21 and 29 and keeping the length of name the same in stringLength
ad 1) The javadocs are a very good reference, here java.lang.String.substring (...):
substring
public String substring(int beginIndex, int endIndex)
Returns a new string that is a substring of this string. The
substring begins at the specified
beginIndex and extends to the
character at index endIndex - 1. Thus
the length of the substring is
endIndex-beginIndex.
The benefit, in excluding the index of the end, is, that you can sequently iterate over values:
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);
that's correct substring works in this way:
public String substring(int beginIndex, int endIndex)
Returns a new string that is a
substring of this string. The
substring begins at the specified
beginIndex and extends to the
character at index endIndex - 1. Thus
the length of the substring is
endIndex-beginIndex.
so for substring(0, 7) it takes 0..6 chars from string
Notice that this is really bad practice to modify iterate's value in for-loop (i++ inside for-loop-body). If after space you haven't any other chars, you'll encounter exception
ad 2)
You don't change i itself, but name gets truncated here:
name = name.substring (0, i-1) + c + name.substring(i+1, stringLength);
but the outer loop isn't informed about the new length.
ad 3) (Code-review):
You should declare and initialize your variables as late as possible, and mark as much as possible final. This tells you, that you don't have to worry about them, after they're initialized.
Given this code:
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);
}
}
you would have get an error message, for name being final. Maybe this would have prevented you to accidentially get out of sync with the length.
modified, to have a mutable upName, but iterating over name:
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);
gives you, for input "honky tonky" the output "HonkyTonky", which would have led you to the way, substring (from, to) works, maybe. :)