String.split replication: OutOfBoundsException - java

For my CompSci class, we're making a Would You Rather? function for our chatbot project. The String.split() method works well for this, but we get bonus points if we can do it without it. I decided to go about this by just creating a method that replicated String.split.
private String[] separate (String phrase, String omit1, String omit2)
{
int c = 0;
//gets rid of leading and trailing whitespace, replaces target characters
//with the # character
phrase = phrase.trim();
phrase = phrase.replace(omit1, "#");
phrase = phrase.replace(omit2, "#");
//detects the number of phrases to be included in the array
for (int i = 0; i < phrase.length(); i++)
if (phrase.charAt(i) == '#')
c++;
//creates array list based on number of phrases
String[] phraseList = new String[c];
c = 0;
//builds phrases from characters found between occurrences
//of the # character
for (int i = 0; i < phrase.length(); i++)
{
if (phrase.charAt(i) == '#')
c++;
else if (phrase.charAt(i) != '#')
phraseList[c] += phrase.charAt(i);
}
return phraseList;
}
Whenever I use this method with the phrase "Would you rather have tea, eat cookie, or push up?" (omit1 being "," and omit2 being "or") it throws this Exception:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at Magpie.separate(Magpie.java:306)
at Magpie.getResponse(Magpie.java:44)
at MagpieRunner.main(MagpieRunner.java:24)
I realize that this has something to do with the counter for the phraseList array, but my attempts to fix it have so far been to no avail.
Any Help?

because if you have even 1 # you will have 2 strings so you need to do c+1 while creating a new array
Like
//creates array list based on number of phrases
String[] phraseList = new String[c+1];
c = 0;
you should use replaceAll(omit1,"#") and not replace(omit1,"#") & replace(omit2,"#")
Can you give more information on where the null is coming ?
Edit:
Have you tried something like ?
phraseList[0]="";
for(int i = 0; i < phrase.length(); i++)
{
if(phrase.charAt(i) == '#')
{
c++;
phraseList[c]="";
}else if(phrase.charAt(i) != '#')
{
phraseList[c] += phrase.charAt(i);
}
}

Think of it like commas separating a list:
1 , 2 , 3 , 4 , 5 , 6
If you count the commas, you'll find there are five; but there are six entries in the list. That's because commas separate the entries, but you still have one on each end.
Or think in terms of fence posts and panels: five posts, four panels.
When you create your array to store the phrases, you need one more entry than you had split points, to make sure you have room for all the phrases.
But it would be easier to avoid this entirely and return a List<String> rather than a String[]. That way, you don't need to know the size in advance.

Since other answers showed you what's wrong with your code, here is a cleaner way of separating string that you might like and that behaves more like the actual split() method:
private String[] separate(String phrase, String delim) {
List<String> tokens = new ArrayList<String>();
// add delimiter to the end of the string
// so last token will be included properly
phrase += delim;
// start from index of first deliminator
// i is the index for the deliminator
// j is the index for the first char of the expression before deliminator
int i, j = 0;
// while there are deliminators
while( (i = phrase.indexOf(delim, j)) != -1) {
// obtain the current token from j to deliminator location
String token = phrase.substring(j, i);
// trim leading/trailing spaces of the token and make sure it has any chars
// if it does, add the token to list
if(token.trim().length() != 0) {
tokens.add(token);
}
// update j to the first character after the deliminator
j = i + delim.length();
}
return tokens.toArray(new String[0]);
}

why not use StringTokenizer? (Below is an example from Java doc)
The following is one example of the use of the tokenizer. The code:
StringTokenizer st = new StringTokenizer("this is a test");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
prints the following output:
this
is
a
test

Arrays are indexed starting from 0, but the length of the array is determined with an initial value of 1.
So even though c gives you the number of phrases, its actually the number of indices in the array (since c starts from 0) and not the actual length. The actual length will be c + 1 (since length is calculated starting from 1)
Index 0 | 1 | 2 | 3 | 4
Length 1 | 2 | 3 | 4 | 5
For example, if c = 4 (Index = 4), your String[] will have length 4, when it should be 5. This is what throws that ArrayIndexOutOfBounds. Hope this helps :)

Related

How to restart a for loop halfway through it's processing? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I want to restart my for-loop. I have a homework problem, in which I have to tell the coordinates of user given word (one alphabet at a time) in a 2D array of A to Z.
for example : if the user gives a word "GREAT", then the program have to print the coordinates of each letter's location in a jagged array. (G - 1,1 , R - 3,2 , E - 2,1, A - 0,0 , T - 3,4)
Using nested for loops, I'm able to print forward characters (what I mean is, the word "GOT" have characters going from A to Z) and if I try "GET" (here, after 'G', 'E' is going backward), the program stops after 'G'. So, I guess if I could restart the loop after each letter's coordinates is printed, I could print all the coordinates.
`//2D array
char a[][] = {{'A','B','C','D','E'},{'F','G','H','I','J'},{'K','L','M','N','O'},{'P','Q','R','S','T'},{'U','V','W','X','Y'},{'Z'}};
//if the user given word is GET,
//then the output should be
//G-1,1
//E-0,5
//T-3,5`
You don't need to restart a loop for this as it would be very inefficient to have an individual loop for each character in your word.
The way to solve this is to use a java map where the key is the character and the value is the entry in your initial array.
Just create a class call WordCoordinatesLocator (or whatever sounds good to you)) that will take your bi-dimensional array and build up the Map in the constructor. Save the map as an instance variable then expose a public method say getCoordinates(String word) that will access the map for each character and build up your response.
You may want to throw an exception if you get invalid characters: characters not included in the original alphabet array.
Then create a unit test to prove it is working as expected.
There are several way to do this.
A simple method is you can go for each char in the word and print its position.
Why do you need to restart the loop if you check for each char.
You can use java maps as said above or even hashtable but this is not a big task.
A simple code that can help you.
String word = "GET";
char a[][] = {{'A','B','C','D','E',' '},{'F','G','H','I','J',' '},{'K','L','M','N','O',' '},{'P','Q','R','S','T',' '},{'U','V','W','X','Y',' '},{'Z',' ',' ',' ',' ',' '}};
int l=0;
while(l<word.length()) {
for (int i = 0 ; i < 6; i++)
for(int j = 0 ; j < 6 ; j++)
if (word.charAt(l) == a[i][j])
System.out.println(i + " " + j);
l++;
}
You can even use switch or multiple if else lol...
Since The last row is special,it contain only one char Z, so we remove from the two-dimensional array,then the array will be a 5 * 5 array.
public static void print(char[][] array, String input) {
if (null == input || input.isEmpty()) {
return;
}
for (int i = 0; i < input.length(); i++) {
char var0 = input.charAt(i);
// Z is special we check first
if (var0 == 'Z') {
System.out.println("Z-6,1");
continue;
}
// Traversing the array to find coordinate
for (int row = 0; row < 5; row++) {
for (int clo = 0; clo < 5; clo++) {
char var1 = array[row][clo];
if (var0 == var1) {
System.out.println(var0 + "-" + row + "," + clo);
break;
}
}
}
}
}

How to delete spaces In an 2D-Array in Java?

I have a text file. I am reading it then placing it into a 2D-Array. There are spaces. I need to get rid of those spaces. But I can't use trim properly. Here is my code:
while ((line = br.readLine() ) != null ){
char[] row = line.toCharArray();
line.trim();
int counter = 0;
for (int i = 0; i < row.length; i++) {
maze[counter][i] = row[i];
System.out.print(maze[i]);
counter++;
}
System.out.printf("%n");
}
The output is as follows:
1 1 1 0
0 0 1 0
0 0 1 0
0 9 1 0
The elements in the text file I read has one space between each other. But I get too many spaces as output. I need to get this as
1110
0010
0010
0910
I think I should use trim method, but I could not figure it out.
You can use String#split with a regular expression of something like \s+, for example...
String text = "1 1 1 0";
String elements[] = text.split("\\s+");
for (String value : elements) {
System.out.println("[" + value + "]");
}
Which outputs
[1]
[1]
[1]
[0]
(The braces are there to demonstrate that no spaces remain)
In your example I might still be tempted to still us line = line.trim(); to ensure that there are no leading or trailing space which might cause empty values to be included...
You can use (string).replace(" ", '\0') to replace all spaces with blanks
For example:
String line = "1 2 2 3 4 2 122 23 3 3 3 3"; //example
line = line.replace(' ', '\0'); //'\0' is the key for blank (or nothing)
System.out.println(line);
will produce
122342122233333
This will get rid of the spaces and only use the valid input (i.e. the numbers). It says row, but the only input will be the same characters.
Hope this helps.
Quickest way for me would be to just use a nested loop to print each element of the array individually. E.g.
String [][] maze = new String [4][4];
for (int i = 0; i < maze.length; i++) {
maze[i][0] = "1";
maze[i][1] = "0";
maze[i][2] = "1";
maze[i][3] = "0";
}
for (int k =0;k<maze.length;++k){
for(int j=0;j<maze.length;++j)
{
System.out.print(maze[k][j]);
}
System.out.println();
}

Avoiding duplicates without Sets?

I am in a beginner Java class and I haven't gotten the chance to learn how to avoid duplicated values when storing values inside arrays.
String[] newAlphabet = new String[26];
for(int I = 0; I < newAlphabet.length; I++){
int random = (65 + (int)(Math.random() * ((90 - 65) + 1));
char ascii = (char)random;
String letters = ascii + "";
if(letters != newAlphabet[0] && letters != newAlphabet[1] ... so on and so on until
newAlphabet[25])
newAlphabet[I] = letters;
}//end
So this is my pseudo code for part of my program and the point of it is to avoid having duplicated letters inside the array.
The problem that I am having is inside the if statement. Instead of typing letters != newAlphabet[] to 25, is there another way of doing it?
I have seen some of the forums in stackedoverflow that I should use HashSet but I have not learned that? I can ask my teacher if I am allowed but is there another way to avoid this problem?
I have been thinking of using for-each loop to search through all the elements in the array but I haven't thought out the plan long enough if it's valid.
As you are talking about a beginner Java class, I am assuming you are fairly new to programming. So, rather than just give you a library function that will do it for you, let's walk through the steps of how to do this with just the basic code so you can get a better idea of what is going on behind the scenes.
Firstly, for any repetitive action, think loops. You want to check, for each letter in your new alphabet, if the one you are about to add matches it. So...
boolean exists = false; //indicates whether we have found a match
for (int j = 0; j < 26; j++) { //for each letter in the new alphabet
//true if this one, or a previous one is a match
exists = exists || letters == newAlphabet[i];
}
//if we don't have a match, add the new letter
if (!exists) newAlphabet[I] = letters;
Now, as you are building up your new alphabet as we go, we don't have a full 26 letters for most cases of running this code, so only check the parts of the new alphabet we have defined:
boolean exists = false;
for (int j = 0; j < I; j++) { //note in this line we stop before the insertion point
exists = exists || letters == newAlphabet[i];
}
if (!exists) newAlphabet[I] = letters;
Finally, we don't need to keep checking if we have already found a match, so we can change the loop to stop when we have found a match:
boolean exists = false;
int j = 0;
while (!exists && j < I) { //we now also stop if we have already found a match
exists = letters == newAlphabet[i];
//as we are stopping at the first match,
//we no longer need to allow for previous matches
}
if (!exists) newAlphabet[I] = letters;
You could use the asList method:
if( Arrays.asList(newAlphabet).contains(letters) ) {
newAlphabet[I] = letters;
}
It's not the most efficient, but since your array is only 26 elements long, I would favor clarity over efficiency.
Some explanation: asList is a static method on the Arrays class. This just means that we don't have to create an Arrays object to call it. We simply say Arrays.asList() and pass it the arguments. The asList method takes an array (newAlhpabet in this case) as a parameter, and builds a java.util.List out of it. This means that we can call List methods on the return value. contains() is a method on List that returns true if the List contains an element that is equal to the parameter (letters in this case).
Based on this line it looks like all you're trying to do is produce the letters A to Z in some other order:
int random = (65 + (int)(Math.random() * ((90 - 65) + 1));
If I'm understanding that right, then really all you're trying to do is shuffle the alphabet:
// Initialize new alphabet array
String originalAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] newAlphabet = originalAlphabet.toCharArray();
// Shuffle the new alphabet by swapping each character to a random position
for (int i=0; i<26; i++) {
int j = (int)(Math.random() * 26);
char temp = newAlphabet[i];
newAlphabet[i] = newAlphabet[j];
newAlphabet[j] = temp;
}
// Print the new alphabet
for (int i=0; i<26; i++) {
System.out.print(newAlphabet[i]);
}
System.out.println();
Here's a sample output: VYMTBIPWHKZNGUCDLRAQFSOEJX
You have a couple options.
Loop through the array and do basically what you're doing now.
Insert the characters in sorted order so you can perform binary search to determine if a letter is already in the list. As a bonus, if you use option 2, you'll already know the insertion point.
Check out Arrays.binarySearch(): http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html
You could use this :
if(Arrays.binarySearch(newAlphabet, letters) < 0){
newAlphabet[I] = letters;
}
You should either include a while loop to make sure each index of the array is filled before moving to the next or you could make use of the return value of Arrays.binarySearch which is (-(insertion index) - 1) to fill the array and exit when the array is filled up.

it works in c but not in java?

The following code to gets the vowel deleted from array, and the array rearranges itself.
public static void main(String[] args) {
int a = 0,k=0;
Scanner obj = new Scanner(System.in);
System.out.println("enter string");
String s= obj.nextLine();
char c[]=new char[s.length()];
c = s.toCharArray();
for(int i =0; i<s.length();i++){
if(c[i]=='a'|| c[i]=='i'|| c[i]=='o'||c[i]=='u'||c[i]=='e'){
for(int j=0;j<s.length();j++){
c[j]=c[j+1];
}
}
}
In the j for loop, you have this statement:
c[j]=c[j+1];
The ArrayIndexOutOfBoundsException comes when j is the last possible index, and you attempt to access the index element one too high.
You can stop when you get to s.length() - 1.
Additionally, you are shifting everything down, not just past where you found a vowel. Start your j for loop not at 0, but at i.
for(int j=i;j<s.length() - 1;j++){
You'll also have to decide what to do with the end of the array, which is not getting overwritten with anything here.
You can't change an array by pointing one location to the next: c[j]=c[j+1]; That line will only replace the character at c[j] but it won't remove that position entirely from the array. You'd need to create a new array with the vowels removed.
This also explains the out-of-bounds exception which happens when you're at the end of the array. You're trying to access the element at j + 1 but that is outside the array.
for(int j=0;j<s.length();j++){
c[j]=c[j+1];
}
Your problem is here. c[j+1] is referencing a location beyond the end of your array. When you assign c[j] a value from that location, you're trying to retrieve a location that does not exist. This causes an ArrayOutOfBoundsException.
You can achieve the same effect by transforming the string with a RegExp:
s.replaceAll("[aioue]","");
This works in C because the size of the string with strlen is one less than the actual size including the \0 at the end. When you copy all the characters down, you are moving the termination character as well. Java doesn't use termination characters and doesn't have a character which is beyond the end of the String.
In Java it is more natural to write a regular expression like this and work with Strings from the start.
System.out.println("enter string");
Scanner scan = new Scanner(System.in);
String line = scan.nextLine();
String noVowels = line.replaceAll("[AEIOUaeiou]", "");
System.out.println("Without vowels the line is '" + noVowels + "'");
Or you can use this regex
// (?i) mean case insensitive
String noVowels = line.replaceAll("(?i)[aeiou]", "");
you have the length of string is 4 and you put it on c[s.length] mean it start from 0-3 array indexing. in the second loop you swap the c[j+1] int c[j]. it cause array index out of bounds.
try this in the second loop
for (int j = 0; j < s.length()-1; j++)
{
System.out.println(c[j+1]);
c[j] = c[j + 1];
}

Why am I getting java.lang.StringIndexOutOfBoundsException?

I want to write a program that prints words incrementally until a complete sentence appears. For example : I need to write (input), and output:
I
I need
I need to
I need to write.
Here is my code:
public static void main(String[] args) {
String sentence = "I need to write.";
int len = sentence.length();
int numSpace=0;
System.out.println(sentence);
System.out.println(len);
for(int k=0; k<len; k++){
if(sentence.charAt(k)!='\t')
continue;
numSpace++;
}
System.out.println("Found "+numSpace +"\t in the string.");
int n=1;
for (int m = 1; m <=3; m++) {
n=sentence.indexOf('\t',n-1);
System.out.println("ligne"+m+sentence.substring(0, n));
}
}
and this is what I get:
I need to write.
16
Found 0 in the string.
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: -1 at
java.lang.String.substring(String.java:1937) at
split1.Split1.main(Split1.java:36) Java Result: 1 BUILD SUCCESSFUL
(total time: 0 seconds)
I don't understand why numSpace doesn't count the occurrences of spaces, nor why I don't get the correct output (even if I replace numSpace by 3 for example).
You don't have a \t character, so indexOf(..) returns -1
You try a substring from 0 to -1 - fails
The solution is to check:
if (n > -1) {
System.out.prinltn(...);
}
Your loop looking for numSpace is incorrect. You are looking for a \t which is a tab character, of which there are none in the string.
Further, when you loop in the bottom, you get an exception because you are trying to parse by that same\t, which will again return no results. The value of n in n=sentence.indexOf('\t',n-1); is going to return -1 which means "there is not last index of what you are looking for". Then you try to get an actual substring with the value of -1 which is an invalid substring, so you get an exception.
You are mistaken by the concept of \t which is an escape sequence for a horizontal tab and not for a whitespace character (space). Searching for ' ' would do the trick and find the whitespaces in your sentence.
This looks like homework, so my answer is a hint.
Hint: read the javadoc for String.indexOf paying attention to what it says about the value returned when the string / character is not found.
(In fact - even if this is not formal homework, you are clearly a Java beginner. And beginners need to learn that the javadocs are the first place to look when using an unfamiliar method.)
The easiest way to solve this I guess would be to split the String first by using the function String.split. Something like this:
static void sentence(String snt) {
String[] split = snt.split(" ");
for (int i = 0; i < split.length; i++) {
for (int j = 0; j <= i; j++) {
if (i == 1 && j == 0) System.out.print(split[j]);
else System.out.printf(" %s", split[j]);
}
}
}
As other people pointed out. You are counting every characters except tabs(\t) as a space. You need to check for spaces by
if (sentence.charAt(k) == ' ')
\t represents a tab. To look for a space, just use ' '.
.indexOf() returns -1 if it can't find a character in the string. So we keep looping until .indexOf() returns -1.
Use of continue wasn't really needed here. We increment numSpaces when we encounter a space.
System.out.format is useful when we want to mix literal strings and variables. No ugly +s needed.
String sentence = "I need to write.";
int len = sentence.length();
int numSpace = 0;
for (int k = 0; k < len; k++) {
if (sentence.charAt(k) == ' ') {
numSpace++;
}
}
System.out.format("Found %s in the string.\n", numSpace);
int index = sentence.indexOf(' ');
while(index > -1) {
System.out.println(sentence.substring(0, index));
index = sentence.indexOf(' ', index + 1);
}
System.out.println(sentence);
}
Try this, it should pretty much do what you want. I figure you have already finished this so I just made the code real fast. Read the comments for the reasons behind the code.
public static void main(String[] args) {
String sentence = "I need to write.";
int len = sentence.length();
String[] broken = sentence.split(" "); //Doing this instead of the counting of characters is just easier...
/*
* The split method makes it where it populates the array based on either side of a " "
* (blank space) so at the array index of 0 would be 'I' at 1 would be "need", etc.
*/
boolean done = false;
int n = 0;
while (!done) { // While done is false do the below
for (int i = 0; i <= n; i++) { //This prints out the below however many times the count of 'n' is.
/*
* The reason behind this is so that it will print just 'I' the first time when
* 'n' is 0 (because it only prints once starting at 0, which is 'I') but when 'n' is
* 1 it goes through twice making it print 2 times ('I' then 'need") and so on and so
* forth.
*/
System.out.print(broken[i] + " ");
}
System.out.println(); // Since the above method is a print this puts an '\n' (enter) moving the next prints on the next line
n++; //Makes 'n' go up so that it is larger for the next go around
if (n == broken.length) { //the '.length' portion says how many indexes there are in the array broken
/* If you don't have this then the 'while' will go on forever. basically when 'n' hits
* the same number as the amount of words in the array it stops printing.
*/
done = true;
}
}
}

Categories

Resources