Novice programmer needs advice: "String index out of range" - Java - java

I'm pretty new to programming and I'm getting a error which I'm sure is a easy fix for more experienced people.
Here is what I have:
import java.io.*;
import java.util.Scanner;
public class ReadNamesFile
{
public static void main(String[] args) throws IOException {
// make the names.csv comma-separated-values file available for reading
FileReader f = new FileReader("names.csv");
BufferedReader r = new BufferedReader(f);
//
String lastName="unknown", firstName="unknown", office="unknown";
// get first line
String line = r.readLine();
// process lines until end-of-file occurs
while ( line != null )
{
// get the last name on the line
//
// position of first comma
int positionOfComma = line.indexOf(",");
// extract the last name as a substring
lastName = line.substring(0,positionOfComma);
// truncate the line removing the name and comma
line = line.substring(positionOfComma+1);
// extract the first name as a substring
firstName = line.substring(0,positionOfComma);
// truncate the line removing the name and comma
line = line.substring(positionOfComma+1);
// extract the office number as a substring
office = line.substring(0,positionOfComma);
// truncate the line removing the name and comma
line = line.substring(positionOfComma+2);
//
//
//
// display the information about each person
System.out.print("\nlast name = "+lastName);
System.out.print("\t first name = "+firstName);
System.out.print("\t office = "+office);
System.out.println();
//
// get the next line
line = r.readLine();
}
}
}
Basically, it finds the last name, first name and office number in a .csv file and prints them out.
When I compile I don't get any errors but when I run it I get:
java.lang.StringIndexOutOfBoundsException: String index out of range: 7
at java.lang.String.substring(String.java:1955)
at ReadNamesFile.main(ReadNamesFile.java:34)
Before trying to do the office number part, the first two (last and first name) printed out fine but the office number doesn't seem to work.
Any ideas?
Edit: Thanks for all the posts guys, I still can't really figure it out though. Can someone post something really dumbed down? I've been trying to fix this for an hour now and I can't get it.

Let's work by example, what issues you have with your code.
Eg: line: Overflow,stack
{ length: 14 }
Taking your program statements line by line -
int positionOfComma = line.indexOf(","); // returns 9
lastName = line.substring(0,positionOfComma); // should be actually postionOfComma-1
Now lastName has Overflow. positionOfComma has 9.
line = line.substring(positionOfComma+1);
Now line has stack.
firstName = line.substring(0,positionOfComma);
Asking substring from 0 to 9. But stack is only of length 5. This will cause String index out of range exeception. Hope you understood where you are doing wrong.

From JavaDoc:
(StringIndexOutOfBoundsException) - Thrown by String methods to
indicate that an index is either negative or greater than the size of
the string.
In your case, one of your calls to .substring is being given a value that is >= the length of the string. If line #34 is a comment, then it's the line above #34.

You need to:
a) Make sure you handle the case if you DON'T find a comma (i.e. if you cannot find and extract a lastName and/or firstName string)
b) Make sure the value of "positionOfComma + N" never exceeds the length of the string.
A couple of "if" blocks and/or "continue" statements will do the trick nicely ;-)

You correctly find positionOfComma, but then that logic applies to the original value of line. When you remove the last name and comma, positionOfComma is no longer correct as it applies to the old value of line.

int positionOfComma = line.indexOf(",");
this line of code might not find a comma and then positionOfComma will be -1. Next you substring something with (0,-1) - eeek no wonder it gives StringIndexOutOfBoundsException. Use something like:
int positionOfComma = 0;
if(line.indexOf(",")!=-1)
{
positionOfComma = line.indexOf(",");
}
You do have to do lots of checking of things sometimes especially when the data is whacked :(
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#indexOf(java.lang.String)
PS I'm sure someone clever can make my coding look shabby but you get the point I hope :)

Related

Stop printing line of text from a file after a character appears a second time

I am currently trying to stop printing a line of text after a , character is read on that line a second time from a text file. Example; 14, "Stanley #2 Philips Screwdriver", true, 6.95. Stop reading and print out the text after the , character is read a second time. So the output text should look like 14, "Stanley #2 Philips Screwdriver". I tried to use a limit on the regex to achieve this but, it just omits all the commas and prints out the entire text. This is what my code looks like so far;
public static void fileReader() throws FileNotFoundException {
File file = new File("/Users/14077/Downloads/inventory.txt");
Scanner scan = new Scanner(file);
String test = "4452";
while (scan.hasNext()) {
String line = scan.nextLine();
String[] itemID = line.split(",", 5); //attempt to use a regex limit
if(itemID[0].equals(test)) {
for(String a : itemID)
System.out.println(a);
}//end if
}//end while
}//end fileReader
I also tried to print just part of the text up until the first comma like;
String itemID[] = line.split(",", 5);
System.out.println(itemID[0]);
But no luck, it just prints 14. Please any help will be appreciated.
What about something using String.indexOf and String.substring functions (https://docs.oracle.com/javase/7/docs/api/java/lang/String.html)
int indexSecondOccurence = line.indexOf(",", line.indexOf(",") + 1);
System.out.println(line.substring(0, indexSecondOccurence + 1));
I'd suggest to modify your code as follows.
...
String[] itemID = line.split(",", 3); //attempt to use a regex limit
if(itemID[0].equals(test)) {
System.out.println(String.join (",", itemID[0],itemID[1]));
}
...
The split() call will produce an array with maximum 3 elements. First two will be the string pieces that you need. The last element is the remaining "tail" of the original string.
Now we only need to merge the pieces back with the join() method.
Hope this helps.

What's an elegant way to parse this text in java?

Disclaimer:
The parsing-problem described in here is very simple. This question does not simply ask for a way to achieve the parsing. - That's almost straightforward - Instead, it asks for an elegant way. That elegant way would probably be one which does not first read line-wise and then parse each line on its own, as this is obviously not necessary. However, is this elegant way possible with ready to use standard classes?
Question:
I have to parse text of the following form in java (there is more than these 3 records; records can have way more lines than these examples):
5
Dominik 3
Markus 3 2
Reiner 1 2
Samantha 4
Thomas 3
4
Babette 1 4
Diana 3 4
Magan 2
Thomas 2 4
The first number n is the number of lines in the record directly following. Each record consists of a name and then 0 to n integers.
I thought that using java.util.Scanner is a natural choice, but it leads to the nastiness that when using hasNextInt() and hasNext() to determine if a line is started, I can't distinguish if a read number is the header of the next record or it's the last number behind the last name of the previous record. Example from above:
...
Thomas 3
4
...
Here, I don't know how to tell if the 3 and the 4 is a header or belongs to the current line of Thomas.
Sure I can first read line by line, put them into another Scanner, and then read them again, but this effectively parses the whole data twice, which looks ugly to me. Is there a better way?
I would need something like a flag which tells me if a line break was encountered during the last delimiter skipping operation.
Read the file using FileReader and BufferedReader and then start checking :
outer loop -->while readLine is not null
if line matches //d+ --> read value of number and put it into count
from 0 to count do what you want to do // inner loop
Instead of reading into a separate scanner, you can read to end of line, and use String.split, like this:
while (scanner.hasNextInt()) {
int count = scanner.nextInt();
for (int i = 0 ; i != count ; i++) {
if (!scanner.hasNext()) throw new IllegalStateException("expected a name");
String name = scanner.next();
List<Integer> numbers = new ArrayList<Integer>();
for (String numStr : scanner.readLine().split(" ")) {
numbers.add(Integer.parseInt(numStr));
}
... // Do something with name and numbers
}
}
This approach avoids the need to detect the difference between the last int on a line vs. the first integer on next line by calling readLine() after reading a name, i.e. in the middle of reading a line.
File file = new File("records.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
/* Read file one line at a time */
while((line = reader.readLine()) != null){
int noOfRecords = Integer.parseInt(line);
/* read the next n lines in a loop */
while(noOfRecords != 0){
line = reader.readLine();
String[] tokens = line.split(" ");
noOfRecords--;
// do what you need to do with names and numbers
}
}
Here we're reading one line at a time, so the first time we read a line it will be an int (call it as n), from there read the next n lines in some inner loop. Once it's done with this inner loop it will come outside and the next time you read a line it's definitely another int or EOF. That way you don't have to deal with integer parsing exceptions and we'll read all the lines only once :)

IndexOf(), String index out of bounds: -1

I have no idea what is happening. I have a list of products along with a number separated with a tab. When I use indexOf() to find the tab, I get a String index out of bounds error, and it says the index is -1. Here's the code:
package taxes;
import java.util.*;
import java.io.*;
public class Taxes {
public static void main(String[] args) throws IOException {
//File aFile = new File("H:\\java\\PrimeNumbers\\build\\classes\\primenumbers\\priceList.txt");
File aFile = new File("C:\\Users\\Tim\\Documents\\NetBeansProjects\\Taxes\\src\\taxes\\priceList.txt");
priceChange(aFile);
}
static void priceChange(File inFile) throws IOException {
Scanner scan = new Scanner("priceList.txt");
char tab = '\t';
while (scan.hasNextLine()) {
String line = scan.nextLine();
int a = line.indexOf(tab);
String productName = line.substring(0,a);
String priceTag = line.substring(a);
}
}
}
And here's the input:
Plyer set 10
Jaw Locking Plyers 10
Cable Cutter 7
16 oz. Hammer 5
64 oz. Dead Blow Hammer 12
Sledge Hammer 20
Cordless Drill 22
Hex Impact Driver 50
Drill Bit Set 30
Miter Saw 200
Circular Saw 40
Scanner scan = new Scanner("priceList.txt");
This line of code is wrong. This Scanner instance will scan the String "priceList.txt". It doesn't contain a tab, therefore indexOf returns -1.
Change it to:
Scanner scan = new Scanner(inFile);
to use the method argument, that is the desired file instance of your priceList.txt.
String.indexOf(char) will return -1 if an instance isn't found.
You need to check before proceeding that a isn't negative.
You can read more about the indexOf method here and here.
Because you are checking int a = line.indexOf(tab) in every iteration of the while loop, there has to be a tab in every single line of your document in order for the error to be prevented.
When your while (scan.hasNextLine()) loop runs into a line with no tab in it, the index is going to be -1, and you get the StringIndexOutOfBoundsException when trying to get line.substring(0,a), with a being -1.
while (scan.hasNextLine()) {
String line = scan.nextLine();
int a = line.indexOf(tab);
if(a!=-1) {
String productName = line.substring(0,a);
String priceTag = line.substring(a);
}
}
If you look very carefully at the input lines you have posted, you'll see
Jaw Locking Plyers 10
...
Cordless Drill 22
Hex Impact Driver 50
Drill Bit Set 30
that the "Hex Impact Driver" line has the price two characters to the right of the one in the lines before and after. This is an indication that "50" does not start at a tab position whereas "10" is at such a position, the next after the one for "22" and "30".
The Q&A editor does preserve TABs, so your editor preserves them as well, and your program should be able to recognize a TAB in the input lines.
That said, a TAB entered by hand (!) is a very poor choice for a separator. As you have experienced, text file presentation doesn't show it. It would be much better to use a special character that does not occur in the product names. Plausible choices are '|', '#', and '\'.
Another good way would be to use pattern matching to find the numeric price at the end of a line - the product name is what remains after removing the price and calling trim() on the remaining string.
Since it has been verified that indexOf(tab) returns -1, the question is why does the line of text not contain t a tab when you seem certain that it does?
The answer is most likely the settings on your IDE. For instance, I usually configure Netbeans to convert a tab to three spaces. So if you typed this input file yourself within an IDE, the tab-to-space conversion is likely the problem.
Work around:
If we copy/paste some text into Netbeans that includes tabs, the tabs do not get converted to spaces.
The text file could be created with notepad or any other simple text editor to avoid the problem.
Change the settings on your IDE, at least for this project.

How to print the contents at occurence of a substring

I wrote a piece of code to look through a String named line with several lines(hence newline characters) in it. my code prints all locations of the string Context in the line. how do i modify the code to print the occurence
String Context = ("[020t");
int index =0;
int count = 0;
while((index = line.indexOf(Context, index))!= -1)
{
count++;
index += Context.length() -1;
System.out.println(index);
}
System.out.println(count);
A sample line is
[020t 12:23:43 FILE TAKEN
[020t 12:23:44 REGISTRATION END
[0r(1)2[000p[040qe1w3h162[020t*881*11/11/2010*12:24*
*CARD INSERTED*
[020t 12:24:06 CODE ENTERED
11\11\10 12:24 10390011
5061180101607659013 6598
INVALID TRANSACTION, PLEASE CONTACT
YOUR ADMINISTRATOR FOR ADVICE
I intend to pass the lines out to another method. Thanks
If you intend to pass the occurance, split the string based on new line. iterate the resultant string array and check if it starts with your needed string - if so you can add it some list and pass the list to your method

Java - New line loop

I have an array with types and numbers and when printing this is the outcome:
car:1 car:2 car:3 boat:1 boat:2 boat:3 plane:1 plane:2 plane:3
I am looking for a way to determine when the type changes, and then make a new line. which means to print a "\n" after car:3 (and boat:3) so all the vehicles are on their own row.
I am printing all these items with a for-loop like this:
for(Types filename: TypeTable)
{
Scanner s;
s = new Scanner(filename.toString());
while (s.hasNext())
{
System.out.print(s.nextLine()+ " ");
}
and I guess I am in need for some local loop and to save the first type in some temp variable and in a loop print a newline when it changes, but I am kinda stuck.
edit2:
after taking a break and then coming back i managed to fix the problem, and even without having a blank line in beginning. the problem was that i had to define oldTransport in main-class :) ofc you couldnt have known how my structure was. thank you hovercraft of eel :)
Rather than printing the line via System.out.print(...) get the line and put it into a variable. Split it via the String#split(...) method, and compare the first part obtained (the String in the [0] spot of the array obtained from split) with the previous String's first part (that was also saved to a variable). If different, make a new line before printing the line out.
Also, if you are going to extract a nextLine() from the scanner, check for a hasNextLine(), not hasNext().
In pseudocode
String oldTransportation gets assigned ""
while the scanner has a next line
String variable line gets scanner's next line
String array called tokens gets this line split on ":"
String newTransportation gets the [0] item in the tokens array
Check if newTransportation equals(...) oldTransportation,
if different, call System.out.println().
print the line variable String
oldTransportation gets assigned newTransportation
end while scanner...
Lets keep track of the previous type.
String lastTypeName = "";
for(Types filename: TypeTable) {
if(!lastTypeName.equals(filename.toString()) {
lastTypeName = filename.toString();
System.out.println();
}
Scanner s = new Scanner(filename.toString());
while (s.hasNext()) {
System.out.print(s.nextLine()+ " ");
}
s.close();
}
A line break will get printed before the first line, but maybe that is not a problem.

Categories

Resources