What is causing this StringIndexOutOfBoundsException? - java

I am writing a program that takes names from a text file and prints the initials of the names.
The names are in "Last, First M." format, with each name being on a separate line.
Because the text file contains the names of everybody in my class I am not including it in this post.
The error I am receiving is:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 1
at java.lang.String.substring(String.java:1963)
at AS01a.main(AS01a.java:28)
/* My Name
** February 6, 2019
** Class Name
** Assignment Name
** Collaborations: None
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class AS01a{
public static void main(String args[]) throws FileNotFoundException{
String DEFAULT_FILE_NAME = "AS01.txt";
String fileName;
if (args.length != 0)
{ fileName = args[0]; }
else
{ fileName = DEFAULT_FILE_NAME; }
Scanner input = new Scanner(new File(fileName));
String fullName, first, middle, last, initials;
while(input.hasNextLine()){
fullName = input.nextLine();
//Dividing the full name into individual initials
first = fullName.substring(fullName.indexOf(" ")+1, fullName.indexOf(" ")+2);
middle = fullName.substring(fullName.lastIndexOf(" ")+1, fullName.lastIndexOf(" ")+2);
last = fullName.substring(0,1);
//Testing to see if the full name contains a middle name
if(fullName.indexOf(" ") == fullName.lastIndexOf(" ")){
initials = first + ". " + last + ".";
}
else{
initials = first + ". " + middle + ". " + last + ".";
}
if(input.hasNextLine()){
System.out.println(fullName + " yields " + initials);
}
}
}
}
My results come out as expected, the only problem is the errors previously mentioned.

Your StringIndexOutOfBoundsException may be due to the data your receiving as we do not know the "Full Name". If someone doesn't have a first/middle/last name you will get the exception because you are not checking for this before the first middle and last are initialized. Move your initializers into your if statements and see if that helps.
Try this.
while(input.hasNextLine()){
fullName = input.nextLine();
if(fullName.isEmpty())
fullName = input.nextLine();
//Testing to see if the full name contains a middle name
if(fullName.indexOf(" ") == fullName.lastIndexOf(" ")){
first = fullName.substring(fullName.indexOf(" ")+1, fullName.indexOf(" ")+2);
last = fullName.substring(0,1);
initials = first + ". " + last + ".";
}
else{
first = fullName.substring(fullName.indexOf(" ")+1, fullName.indexOf(" ")+2);
middle = fullName.substring(fullName.lastIndexOf(" ")+1, fullName.lastIndexOf(" ")+2);
last = fullName.substring(0,1);
initials = first + ". " + middle + ". " + last + ".";
}
if(input.hasNextLine()){
System.out.println(fullName + " yields " + initials);
}
}

fullName seems to be an empty string, you can easily check this with debugger. And the reason why it's empty is that you probably have a blank line in your file. If it so, you should add empty check like if (fullName.isEmpty()) continue; to iterate over the remaining lines.

Related

how to split string by reading text from file

I am trying to read os-release file on Linux and trying to get the OS version by finding VERSION_ID="12.3" line. I wrote below piece of code but at the last after splitting the string first time I am unable to go further. I reached up to splitting to "12.3" from VERSION_ID, after this I applied split function again and getting "java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 0" error. , Need your help and valuable suggestions.
File fobj2 = new File("C:\\os-release");
if(fobj2.exists() && !fobj2.isDirectory())
{
Scanner sc = new Scanner(fobj2);
while(sc.hasNextLine())
{
String line = sc.nextLine();
//VERSION_ID="12.3"
if(line.contains("VERSION_ID="))
{
System.out.println(" VERSION_ID= " + line );
String [] ver = line.split("=");
if(ver.length > 1)
{
String [] ver_id = line.split("=");
System.out.println(" ver_id.length " + ver_id.length );
System.out.println(" ver_id[0] " + ver_id[0] );
System.out.println(" ver_id[1] " + ver_id[1] );
System.out.println(" ver_id[1].length() " + ver_id[1].length() );
String [] FinalVer1 = ver_id[1].split(".");
System.out.println(" FinalVer1[1].length() " + FinalVer1[1].length() );
System.out.println(" FinalVer1[1] " + FinalVer1[1] );
}
}
}
Here is yet another way to gather the Major and Minor version values from the line String:
String line = "VERSION_ID=\"12.3\"";
// Bring line to lowercase to eliminate possible letter case
// variations (if any) then see if 'version-id' is in the line:
if (line.toLowerCase().contains("version_id")) {
// Remove all whitespaces and double-quotes from line then
// split the line regardless of whether or not there are
// whitespaces before or after the '=' character.
String version = line.replaceAll("[ \"]", "").split("\\s*=\\s*")[1];
//Get version Major.
String major = version.split("[.]")[0];
// Get version Minor.
String minor = version.split("[.]")[1];
// Display contents of all variables
System.out.println("Line: --> " + line);
System.out.println("Version: --> " + version);
System.out.println("Major: --> " + major);
System.out.println("Minor: --> " + minor);
}
Try this !
File fobj2 = new File("C:\\os-release");
if(fobj2.exists() && !fobj2.isDirectory())
{
Scanner sc = new Scanner(fobj2);
while(sc.hasNextLine())
{
String line = sc.nextLine();
//VERSION_ID="12.3"
if(line.contains("VERSION_ID="))
{
System.out.println(" VERSION_ID= " + line );
String [] ver = line.split("=");
if(ver.length > 1)
{
String [] ver_id = line.split("=");
System.out.println(" ver_id.length " + ver_id.length );
System.out.println(" ver_id[0] " + ver_id[0] );
System.out.println(" ver_id[1] " + ver_id[1] );
System.out.println(" ver_id[1].length() " + ver_id[1].length() );
// Here
String [] FinalVer1 = ver_id[1].split("\\.");
System.out.println(" FinalVer1[1].length() " + FinalVer1[1].length() );
System.out.println(" FinalVer1[1] " + FinalVer1[1] );
}
}
}
Just need to escape the dot like this.
I think that when You are using split method on string like "VERSION_ID="12.3"", the output would be: String arr = {"VERSION_ID", "12.3"}. So why are You using the next split with "=" on the ver_id array. Try using ".", from my understanding You are looking for number after the dot.

Beginner Java - Changing String from First Middle Last to Last, First Middle

Trying to work out a homework problem that demands:
Changes a name so that the last name comes first.
Example: "Mary Jane Lee" will return "Lee, Mary Jane".
If name has no spaces, it is returned without change.
After doing some research it seems I can do this with the Split method, but we've not learned that yet.
The thing is I've worked out the code and it seems to work when spaces
and a full name is entered, but when there's no middle name or no spaces to separate the character, I get the error:
when the name entered is simply: Harry Smith
java.lang.StringIndexOutOfBoundsException: String index out of range: -7
and
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
when the name is Sarah
This is my code, but I'm not sure how to fix it:
public class Names {
public static String lastNameFirst(String name) {
int firstIndex = name.indexOf(" ");
int secondIndex = name.indexOf(" ", firstIndex + 1);
String firstName = name.substring(0, name.indexOf(" "));
String middleName = name.substring(firstIndex + 1, secondIndex);
String lastName = name.substring(secondIndex + 1);
String result = "";
result = lastName + ", " + firstName + " " + middleName;
return result;
}
}
Thanks in advance!!
using split and a switch would be a lot easier
String name = "Mary Jane Lee";
String arr[] = name.split (" ");
switch (arr.length) {
case 1:
System.out.println(name);
break;
case 2:
System.out.println(arr[1] + ", " + arr[0]);
break;
default:
System.out.println(arr[2] + ", " + arr[0] + " " + arr[1]);
}
A more robust way is to use lastIndexOf to find the last space:
int lastSpace = name.lastIndexOf(' ');
if (lastSpace != -1) {
String lastName = name.substring(lastSpace + 1);
String partBeforeLastName = name.substring(0, lastSpace);
return lastName + ", " + partBeforeLastName;
} else {
return name;
}
You don't actually really care about the other space (if it's there at all), since the first and middle names stay in the same relative order.
(Generally, there are lots of falsehoods that programmers believe about names; but let's put those aside for the purpose of the exercise.)
Your code assumes that the input String contains at least two spaces. When that assumption is wrong (as in the inputs "Harry Smith" and "Sarah"), you get an exception.
You must check whether firstIndex and secondIndex are positive before using their values.
The problem is that your code excepts that there are 3 names. It does not handle when there are less names.
public static String lastNameFirst(String name)
{
int firstIndex = name.indexOf(" ");
if ( firstIndex >= 0 )
{
int secondIndex = name.indexOf(" ", firstIndex + 1 );
String firstName = name.substring(0, firstIndex);
if ( secondIndex >= 0 ) // we have 3 names
{
String middleName = name.substring(firstIndex + 1, secondIndex);
String lastName = name.substring(secondIndex + 1);
return lastName + ", " + firstName + " " + middleName;
}
else // we have 2 names
{
String lastName = name.substring(firstIndex + 1);
return lastName + ", " + firstName;
}
}
else // have only one name
return name;
}
Should worth trying lastIndexOf(), too:
public static String lastNameFirst(String name)
{
int lastIndex = name.lastIndexOf(" ");
if ( lastIndex >= 0 ) // have at least 2 names
{
String firstNames = name.substring(0,lastIndex);
String lastName = name.substring(lastIndex + 1);
return lastName + ", " + firstNames;
}
}
else // have only one name
return name;
}
Also, could try a different approach, split the name into an array, something like this:
public static String lastNameFirst(String name)
{
String[] parts = name.split(" ");
switch ( parts.length )
{
case 1:
return name;
case 2:
return parts[1] + ", " + parts[0];
case 3:
return parts[2] + ", " + parts[0] + " " + parts[1];
}
}

Looking up a string in a file, then copying lines after it

This is my first time posting to this site, so if I get any formatting wrong, please be easy on me Lol
I'm writing a Java program that needs to look up a part number from an inventory, and then print the part number along with the data following it. The code is only printing out the information at the top of the file, and then repeating my else statement 5 times.
Here is the code:
package inventory;
import java.util.Scanner;
import java.io.*;
public class inventory
{
public static void main(String[] args) throws IOException
{
Scanner keyboard = new Scanner(System.in);
// File Information
String parts;
File inventoryFile;
FileWriter inventoryFW;
PrintWriter inventoryPW;
Scanner inventorySC;
//User Information
String userChoice;
// Part Information
String partID, partFileID, partFileDesc, partFileLoc, partDesc, partLoc;
double partFilePrice, partPrice;
int partFileQuan, partQuan;
userChoice = ("A");
// Loop
if(userChoice.equalsIgnoreCase("Q"))
System.exit(0);
else
while(!userChoice.equalsIgnoreCase("Q"))
{
// Get Employee Decision
System.out.println("Please choose a letter: \n"
+ "L - Look Up Part \n"
+ "A - Add to Inventory File \n"
+ "E - Erase From Inventory File \n"
+ "G - Generate a Sales Slip \n"
+ "I - Add Quantity to Inventory File \n"
+ "D - Display Inventory \n"
+ "Q - Quit \n"
+ "Selection: ");
userChoice = keyboard.nextLine();
// Process User Choice
if(userChoice.equalsIgnoreCase("L"))
{ // Choice L
// Look Up Part
System.out.println("Enter Part I.D. Number: ");
partID = keyboard.nextLine();
// Do until partID is equal to partFileID
parts = "inventoryFile.txt";
inventoryFile = new File(parts);
inventorySC = new Scanner(inventoryFile);
partFileID = "0";
partFileDesc = "0";
partFilePrice = 0;
partFileLoc = "0";
partFileQuan = 0;
while(inventorySC.hasNextLine())
{
String lineFromFile = inventorySC.nextLine();
if(lineFromFile.contains(partID))
{
partFileDesc = inventorySC.nextLine();
partFilePrice = inventorySC.nextDouble();
inventorySC.nextLine();
partFileLoc = inventorySC.nextLine();
partFileQuan = inventorySC.nextInt();
System.out.println("Part I.D. Number: " + partFileID + "\n");
System.out.println("Part Description: " + partFileDesc + "\n"
+ "Part Price: " + partFilePrice + "\n"
+ "Part Location: " + partFileLoc + "\n"
+ "Part Quantity: " + partFileQuan);
}
else
System.out.println("Sorry, this part cannot be found");
}
}
}
}
}
And here is the datafile I am trying to pull from:
1234567
Clutch
45.68
Warehouse B
8
1234
Brake
66.78
Warehouse A
4
For example, if the user entered part number "1234" the program should search for that part number in the file, and then display:
1234
Brake
66.78
Warehouse A
4
Sorry about any poor code formatting, I have been fighting with this for a while now.
Any help would be greatly appreciated.
There are a few issues.
The contains will have multiple matches.
You will print "not found every line" you don't find.
You are not breaking out of the loop.
boolean found = false;
while(inventorySC.hasNextLine()){
String lineFromFile = inventorySC.nextLine();
if(lineFromFile.equals(partID)) {
partFileDesc = inventorySC.nextLine();
partFilePrice = inventorySC.nextLine();
partFileLoc = inventorySC.nextLine();
partFileQuan = inventorySC.nextLine();
System.out.println("Part I.D. Number: " + partFileID + "\n");
System.out.println("Part Description: " + partFileDesc + "\n"
+ "Part Price: " + partFilePrice + "\n"
+ "Part Location: " + partFileLoc + "\n"
+ "Part Quantity: " + partFileQuan);
found = true;
break;
}
}
if(!found)
System.out.println("Sorry, this part cannot be found");
Your issue is that you are only skipping to the next line if the part list doesn't contain your part value. You actually want to skip down 5 lines if the part is not on the 'next line'.
In your "else" statement, you'll just want to call the inventorySC.nextLine(); 4 more times to get to the next place in the file you actually want to check for a part number.
If you want the 'not found' condition to reflect more effectively that the part number actually wasn't found at all, you'll want to move that message to after it could have scanned the whole file. Set a boolean with a name like 'found' to false before the file scan. If you enter your 'contains' condition because there is a part number in the file that contains your input, set the 'found' equal to true.
At the end if the 'found' is still 'false', you can output the 'not found' message.
As MadProgrammer commented above, you'll need to use 'equals' instead of 'contains'- this is why you match on the first entry. When you find a match and output it, you need to exit the while loop using a 'break' - otherwise you output the else value for each line left over (as is happening to you). But there is one other problem in that you may need to read an entire record - not just the first line of the record - when there is no match so you don't get screwed up when an inventory item has a quantity of 1234 when searching for part number 1234.

Printing separate name variations in java?

I am making a programming to print the following
user inputs name like so --> first middle last
prints:
FML
Variation one: LAST, First M.
Variation two: Last, First Middle
Now, I need an if statement so that if just a first name is entered it says "error, incorrect input"
I coded this horribly and extremely unconventional, but hey, this is the first thing I've ever programmed before, so I guess we all start somewhere.
import java.util.Scanner;
public class name {
public static void main(String[]args)
{
Scanner input = new Scanner(System.in);
String fullName = input.nextLine();
String firstName;
String middleName;
String lastName;
//Declares length of entire name
int nameLength = fullName.length();
//Declares int where first space is
int a = fullName.indexOf(" ");
//Declares int where second space is
int b = fullName.lastIndexOf(" ");
//If they equal each other, then there is only one space
if ( a == b )
{
firstName = fullName.substring(0,a);
lastName = fullName.substring(a+1,nameLength);
String firstNameInitial = firstName.substring(0,1);
String lastNameInitial = lastName.substring(0,1);
String upperCaseInitials = (firstNameInitial.toUpperCase() + lastNameInitial.toUpperCase());
firstName = fullName.substring(0,a);
lastName = fullName.substring(b+1,nameLength);
System.out.println("Your initials are: " + upperCaseInitials);
System.out.println("Variation One: " + lastName.toUpperCase() + ", " + firstNameInitial.toUpperCase() + firstName.substring(1,a));
System.out.println("Variation Two: " + lastNameInitial.toUpperCase() + lastName.substring(1,lastName.length()) + ", " + firstNameInitial.toUpperCase() + firstName.substring(1,a));
}
//If a < b then it will notice a middle name exists due to multiple spaces
else if ( a < b )
{
firstName = fullName.substring(0,a);
middleName = fullName.substring(a+1,b);
lastName = fullName.substring(b+1,nameLength);
String firstNameInitial = firstName.substring(0,1);
String middleNameInitial = middleName.substring(0,1);
String lastNameInitial = lastName.substring(0,1);
String upperCaseInitials = (firstNameInitial.toUpperCase() + middleNameInitial.toUpperCase() + lastNameInitial.toUpperCase());
//MNIC = Middle Name Initial Capitalized
String MNIC = middleNameInitial.toUpperCase();
//MNIMFC = Middle Name Initial Minus First Character
String MNIMFC = middleName.substring(1, middleName.length());
System.out.println("Your initials are: " + upperCaseInitials);
System.out.println("Variation One: " + lastName.toUpperCase() + ", " + firstNameInitial.toUpperCase() + firstName.substring(1,a) + " " + middleNameInitial.toUpperCase() + "." );
System.out.println("Variation Two: " + lastNameInitial.toUpperCase() + lastName.substring(1,lastName.length()) + ", " + firstNameInitial.toUpperCase() + firstName.substring(1,a) + " " + MNIC + MNIMFC);
}
}
}
You can use the String.split() function to split a String into its parts along a seperator.
In your case that would be the space (" ")
Try:
Scanner input = new Scanner(System.in);
String fullName = input.nextLine();
String firstName;
String middleName;
String lastName;
String[] parts = fullName.split(" ");
if(parts.length() == 3){
// 3 words were entered, so there is a middle name
}
// ...
You can just add this check
if(fullName.indexOf(" ")==-1 || (fullName.indexOf(" ") == fullName.lastIndexOf(" "))){
// The first check is to check if only firstname was given and the second check is to check if only first and middle names were given.
// If first + middle is a valid scenario, you can remove the second half of the if condition
System.out.println("error, incorrect input");
System.exit(0);
}
before the below statement in your code.
int nameLength = fullName.length();
You can simply check for a == -1. indexOf returns -1 if not found (as per the docs).
if (a == -1)
System.out.println("Error, invalid input!");
else if (a == b)
...
You can narrow down to the condition you stated by following these steps:
Trim the input String fullName before statement int a = fullName.indexOf(" ");
Next check if the index of whitespace (i.e. value of a and b variables) is -1, then you can assume that the input contains only a single word, presumably Firstname
Print the error message "error, incorrect input"
since it's your first attempt, I'll give you a modified version of your code:
public class name {
public static void main(String[]args)
{
Scanner input = new Scanner(System.in);
String fullName = input.nextLine();
String firstName;
String middleName;
String lastName;
//Declares length of entire name
int nameLength = fullName.length();
//Declares int where first space is
int a = fullName.indexOf(" ");
//Declares int where second space is
int b = fullName.lastIndexOf(" ");
/*** Use the split function to split the names with spaces as delimiter **/
String[] n = fullName.split(' ');
firstName = n[0];
if( n.length == 2 ) {
lastName = n[1];
}
if( n.length > 3 ) {
lastName = n[1];
middleName = n[2];
}
String firstNameInitial = firstName.substring(0,1);
String middleNameInitial = middleName.substring(0,1);
String lastNameInitial = lastName.substring(0,1);
String upperCaseInitials = (firstNameInitial.toUpperCase() + middleNameInitial.toUpperCase() + lastNameInitial.toUpperCase());
//MNIC = Middle Name Initial Capitalized
String MNIC = middleNameInitial.toUpperCase();
//MNIMFC = Middle Name Initial Minus First Character
String MNIMFC = middleName.substring(1, middleName.length());
System.out.println("Your initials are: " + upperCaseInitials);
System.out.println("Variation One: " + lastName.toUpperCase() + ", " + firstNameInitial.toUpperCase() + firstName.substring(1,a) + " " + middleNameInitial.toUpperCase() + "." );
System.out.println("Variation Two: " + lastNameInitial.toUpperCase() + lastName.substring(1,lastName.length()) + ", " + firstNameInitial.toUpperCase() + firstName.substring(1,a) + " " + MNIC + MNIMFC);
}
}

Searching a string arrays with an array

I am attempting to search a user input array of text with another user input array of search terms using nested loops and then output the search terms with the number of times they appear in the text along with the percentage of total text. I think I am on the right track and my issue is that the counter is not resetting each time the if statement is true. I am very new to programming -- so I could be completely wrong. Below is the entire program. If anyone could take a look and give me a hand at figuring out what my issue is I would be eternally grateful.
public class termFrequency {
public static void main(String[] args) {
String searchTextPeriod, searchTextComma, searchTextApostrophe, searchTextColon, searchTextExclamation,
searchTextQuestion, searchText, searchTerm;
int counter=0, total, searchIndex=0, termIndex=0;
double percentage=0.0;
String [] searchArray, termArray;
searchText = JOptionPane.showInputDialog("Enter a sentence that is at least 20 words long");
//removes some common punctuation from the searchable text
searchTextPeriod = searchText.replace(".", "");
searchTextComma = searchTextPeriod.replace(",", "");
searchTextApostrophe = searchTextComma.replace("'", " ");
searchTextColon = searchTextApostrophe.replace(":", " ");
searchTextExclamation = searchTextColon.replace("!", "");
searchTextQuestion = searchTextExclamation.replace("?", "");
searchArray = searchTextQuestion.split(" "); //splits the sentence and and puts it into an array
total=searchArray.length;
System.out.println("There are " +total +" words in your sentence");
searchTerm = JOptionPane.showInputDialog("Enter your search terms here seperated by a space");
termArray = searchTerm.split(" ");
DecimalFormat two = new DecimalFormat("#0.00");
boolean found = false;
for (termIndex=0; termIndex<termArray.length; termIndex++)
{
for (searchIndex=0; searchIndex<searchArray.length; searchIndex++)
if (termArray[termIndex].equalsIgnoreCase(searchArray[searchIndex]))
{
counter++;
found = true;
percentage= ((double) counter/(double)total) * 100;
}
if (found)
System.out.println("Search word " + "\'" + termArray[termIndex] + "\' is found " +counter +" times. That is "+ two.format(percentage)+"% of the statement." );
else
System.out.println("Search word " + "\'" + termArray[termIndex] + "\' is not found in the statement.");
}
}
}
}
You have to move the if/else on "found" from the inner loop to the end of the first loop.
You also need to reset the boolean and the counter in the first loop, like that you start the analysis of each new word in termArray with initial values.
for (termIndex=0; termIndex<termArray.length; termIndex++)
{
counter=0; //Reset the counter for each word in termArray
found=false; //Reset the "found" flag for each word in termArray
for (searchIndex=0; searchIndex<searchArray.length; searchIndex++)
if (termArray[termIndex].equalsIgnoreCase(searchArray[searchIndex]))
{
counter++;
percentage= ((double) counter/(double)total) * 100;
found=true
System.out.println("Search word " + "\'" + termArray[termIndex] + "\' is found " +counter +" times. That is "+ two.format(percentage)+"% of the statement." );
}
}
if (found)
System.out.println("Search word " + "\'" + termArray[termIndex] + "\' is found " +counter +" times. That is "+ two.format(percentage)+"% of the statement." );
else
System.out.println("Search word " + "\'" + termArray[termIndex] + "\' is not found in the statement.");
}
By the way you don't really need the "found" var, now if counter == 0 you know that the word has not been found in searchArray.
Move found = false inside of the first loop. that way it will be reset to false with each iteration. Right now if it is ever changed to true it stays true for the rest of the process.

Categories

Resources