Parsing a multiline file - java

Ive to parse a multiline file, structured as follows:
Name Surname
birthdate(int)
Name Surname
birthdate(int)
and so on. I opened the file, getting an ArrayList, and created a class which serves as a data structure, but i don't know how to parse each string, recognising if it is a number or a name. Can you help me?

You can use java.util.Scanner class to read your file
It has helper methods to read various types of input if you know the structure of input data (I assume you know its structure)
Here is a sample code to help you read it from some file with given structure
Scanner s = new Scanner(new File("input.txt"));
while(s.hasNext()) {
System.out.println("First Name : " + s.next() + ", Last Name : " + s.next() + ", Age : " +s.nextInt());
}
s.close();
You can create a class with attributes firstName, lastName and age and assign above values to a new object and add that object in List.
Hope this helps.

I guess, this is the main concern:
i don't know how to parse each string, recognising if it is a number
or a name.
Use isNumeric() function to see if you can parse value to number or leave it as a string. Then parse it accordind to value the function returns.
public static boolean isNumeric(String str) {
try {
double d = Double.parseDouble(str);
} catch(NumberFormatException nfe) {
return false;
}
return true;
}
...
//put data into ArrayList
for (int i = 0; i < data.size(); i++) {
String elem = data.get(i);
boolean isNum = isNumeric(elem);
if (isNum) {
int val = Integer.parseInt(elem);
} else {
//do what you want with `elem`
}
}

Related

What is wrong in my file reading with Scanner class?

Every time I run it, gives this message (( InputMismatchException )) where is the problem from ?
File f = new File("nameList.txt");
try {
PrintWriter out;
out = new PrintWriter(f);
for (int i = 0; i < 4; i++) {
out.printf("Name : %s Age : %d ", "Rezaee-Hadi", 19);
out.println("");
}
out.close();
} catch (IOException ex) {
System.out.println("Exception thrown : " + ex);
}
try {
Scanner in = new Scanner(f);
String name = in.nextLine();
int age = in.nextInt();
for (int i = 0; i < 4; i++) {
System.out.println(name);
System.out.println(age);
}
in.close();
} catch (FileNotFoundException ex) {
System.out.println("Exception thrown : " + ex);
}
You are creating your data file in the following data format:
Name : Rezaee-Hadi Age : 19
Now, it really doesn't matter (to some extent) how you format your data file as long as you realize that you may need to parse that data later on. You really don't need to maintain a header with your data on each file line. We already know that the first piece of data on any file line is to be a Name and the second piece of data on any file line is to be the Age of the person the Name relates to. So, the following is sufficient:
Rezaee-Hadi, 19
If you want, you can place a header as the very first line of the data file so that it can easily be determined what each piece of data on each line relates to, for example:
Name, Age
Rezaee-Hadi, 19
Fred Flintstone, 32
Tom Jones, 66
John Smith, 54
This is actually a typical format for CSV data files.
Keeping with the file data format you are already using:
There is nothing wrong with using the Scanner#nextLine() method. It's a good way to go but you should be iterating through the file line by line using a while loop because you may not always know exactly how many actual data lines are contained within the file, for example:
Scanner in = new Scanner(f);
String dataLine;
while (in.hasNextLine()) {
dataLine = in.nextLine().trim();
// Skip Blank Lines
if (dataLine.equals("")) {
continue;
}
System.out.println(dataLine);
}
This will print all the data lines contained within your file. But this is not what you really want is it. You want to separate the name and age from each line which means then that you need to parse the data from each line. One way (in your case) would be something like this:
String dataLine;
Scanner in = new Scanner(f);
while (in.hasNextLine()) {
dataLine = in.nextLine().trim();
// Skip Blank Lines
if (dataLine.equals("")) {
continue;
}
String[] dataParts = dataLine.replace("Name : " , "").split(" Age : ");
System.out.println("The Person's Name: " + dataParts[0] + System.lineSeparator()
+ "The Person's Age: " + dataParts[1] + System.lineSeparator());
}
In the above code we iterate through the entire data file one line at a time using a while loop. As each line is read into the dataLine string variable it is also trimmed of any leading or trailing whitespaces. Normally we don't want these. We then check to make sure the line is not blank. We don't normally want these either and here we skip past those blank lines by issuing a continue to the while loop so as to immediately initiate another iteration. If the file line line actually contains data then it is held within the dataLine variable.
Now we want to parse that data so as to retrieve the Name and the Age and place them into a String Array. We do this by using the String#split() method but first we get rid of the "Name : " portion of the line using the String#replace() method since we don't want to deal with this text while we parse the line. In the String#split() method we supply a string delimiter to split by and that delimiter is " Age : ".
String[] dataParts = dataLine.replace("Name : " , "").split(" Age : ");
Now when each line is parsed, the Name and Age will be contained within the dataParts[] string array as elements located at index 0 and index 1. We now use these array elements to display the results to console window.
At this point the Age is a string located in the dataParts[] array at index 1 but you may want to convert this age to a Integer (int) type value. To do this you can utilize the Integer.parseInt() or Integer.valueOf() methods but before you do that you should validate the fact the the string you are about to pass to either of these methods is indeed a string numerical integer value. To do this you would utilize the String#matches() method along with a simple little Regular Expression (RegEx):
int age = 0;
if (dataParts[1].matches("\\d+")) {
age = Integer.parseInt(dataParts[1]);
// OR age = Integer.valueOf(dataParts[1]);
System.out.println("Age = " + age);
}
else {
System.out.println("Age is not a numerical value!");
}
The regular expression "\\d+" placed within the String#matches() method basically means, "Is the supplied string a string representation of a integer numerical value?". If the method finds that it is not then boolean false is returned. If it finds that the value supplied is a string integer numerical value then boolean true is returned. Doing things this way will prevent any NumberFormatException's from occurring.
Replace this:
int age=0;
while (in.hasNext()) {
// if the next is a Int,
// print found and the Int
if (in.hasNextInt()) {
age = in.nextInt();
System.out.println("Found Int value :"
+ age);
}
}
in place of this:
int age = in.nextInt();
Then you will not get "InputMismatchException" anymore..

How do I return the number of items found after I do a search?

Please help me to figure out how I can get a count of the result when I do a search against a specific folder?
Also how can I ask the user if they want to perform another search?
// Importing utilities
import java.io.File;
import java.util.*;
public class FileListing
{
public static void main (String[] args)
{
// Creating a Scanner
Scanner keyboard = new Scanner(System.in);
// Specifying search location
File file = new File("D:/Music");
String[] content = file.list();
// Searching for a match
System.out.println("Enter the first few characters of the folder/file to do a lookup");
String userInput = keyboard.nextLine();
// Adding text to say what the user searched for
System.out.println("Below you will find the list of folders/files with a partial match to (" + userInput + ").");
System.out.println();
// Posting the contents
for(String folders : content)
{
if(folders.toUpperCase().startsWith(userInput.toUpperCase()))
{
System.out.println("Name: " + folders);
}
}
}
}
If you want to count your matches you can do the following
int i=0;
// Posting the contents
for(String folders : content)
{
if(folders.toUpperCase().startsWith(userInput.toUpperCase()))
{
System.out.println("Name: " + folders);
i++;
}
}
System.out.println("Total number of results: " + i);`
As for asking the user, consider using a do-while loop in the following format
do{
// your code
// ask user and read his answer on a string called userChoice
}while (userChoice.equals('y'))
Experiment with our suggestions and you will find the answer easily enough!
I would add a variable
int count = 0;
right before the for loop, and just increment it if it's a match.
This should get you started. I am incrementing the variable count each time a match is found. I am also looping forever so it keeps asking the user for more input.
// Importing utilities
import java.io.File;
import java.util.*;
public class FileListing
{
public static void main (String[] args)
{
// Creating a Scanner
Scanner keyboard = new Scanner(System.in);
// Specifying search location
File file = new File("D:/Music");
String[] content = file.list();
while(true){
// Searching for a match
System.out.println("Enter the first few characters of the folder/file to do a lookup");
String userInput = keyboard.nextLine();
// Adding text to say what the user searched for
System.out.println("Below you will find the list of folders/files with a partial match to (" + userInput + ").");
System.out.println();
// Posting the contents
int count=0;
for(String folders : content)
{
if(folders.toUpperCase().startsWith(userInput.toUpperCase()))
{
System.out.println("Name: " + folders);
count++;
}
}
}
}
}
Use a while loop and prompt the user to enter a phrase (such as 'exit') if they want to stop. After reading the user input, check the phrase and call a break if it matches the exit phrase.
Use a variable as Robert suggested to count the total number of files found.

Cannot get values from splitted Array String into a String

I am trying to get the values out of String[] value; into String lastName;, but I get errors and it says java.lang.ArrayIndexOutOfBoundsException: 2
at arduinojava.OpenFile.openCsv(OpenFile.java:51) (lastName = value[2];). Here is my code, but I am not sure if it is going wrong at the split() or declaring the variables or getting the data into another variable.
Also I am calling input.next(); three times for ignoring first row, because otherwise of study of Field of study would also be printed out..
The rows I am trying to share are in a .csv file:
University Firstname Lastname Field of study
Karlsruhe Jerone L Software Engineering
Amsterdam Shahin S Software Engineering
Mannheim Saman K Artificial Intelligence
Furtwangen Omid K Technical Computing
Esslingen Cherelle P Technical Computing
Here's my code:
// Declare Variable
JFileChooser fileChooser = new JFileChooser();
StringBuilder sb = new StringBuilder();
// StringBuilder data = new StringBuilder();
String data = "";
int rowCounter = 0;
String delimiter = ";";
String[] value;
String lastName = "";
/**
* Opencsv csv (comma-seperated values) reader
*/
public void openCsv() throws Exception {
if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
// Get file
File file = fileChooser.getSelectedFile();
// Create a scanner for the file
Scanner input = new Scanner(file);
// Ignore first row
input.next();
input.next();
input.next();
// Read from input
while (input.hasNext()) {
// Gets whole row
// data.append(rowCounter + " " + input.nextLine() + "\n");
data = input.nextLine();
// Split row data
value = data.split(String.valueOf(delimiter));
lastName = value[2];
rowCounter++;
System.out.println(rowCounter + " " + data + "Lastname: " + lastName);
}
input.close();
} else {
sb.append("No file was selected");
}
}
lines are separated by spaces not by semicolon as per your sample. Try in this way to split based on one or more spaces.
data.split("\\s+");
Change the delimiter as shown below:
String delimiter = "\\s+";
EDIT
The CSV file should be in this format. All the values should be enclosed inside double quotes and there should be a valid separator like comma,space,semicolon etc.
"University" "Firstname" "Lastname" "Field of study"
"Karlsruhe" "Jerone" "L" "Software Engineering"
"Amsterdam" "Shahin" "S" "Software Engineering"
Please check if you file is using delimiter as ';' if not add it and try it again, it should work!!
Use OpenCSV Library for read CSV files .Here is a detailed example on read/write CSV files using java by Viral Patel

Filter words from string

I want to filter a string.
Basically when someone types a message, I want certain words to be filtered out, like this:
User types: hey guys lol omg -omg mkdj*Omg*ndid
I want the filter to run and:
Output: hey guys lol - mkdjndid
And I need the filtered words to be loaded from an ArrayList that contains several words to filter out. Now at the moment I am doing if(message.contains(omg)) but that doesn't work if someone types zomg or -omg or similar.
Use replaceAll with a regex built from the bad word:
message = message.replaceAll("(?i)\\b[^\\w -]*" + badWord + "[^\\w -]*\\b", "");
This passes your test case:
public static void main( String[] args ) {
List<String> badWords = Arrays.asList( "omg", "black", "white" );
String message = "hey guys lol omg -omg mkdj*Omg*ndid";
for ( String badWord : badWords ) {
message = message.replaceAll("(?i)\\b[^\\w -]*" + badWord + "[^\\w -]*\\b", "");
}
System.out.println( message );
}
try:
input.replaceAll("(\\*?)[oO][mM][gG](\\*?)", "").split(" ")
Dave gave you the answer already, but I will emphasize the statement here. You will face a problem if you implement your algorithm with a simple for-loop that just replaces the occurrence of the filtered word. As an example, if you filter the word ass in the word 'classic' and replace it with 'butt', the resultant word will be 'clbuttic' which doesn't make any sense. Thus, I would suggest using a word list,like the ones stored in Linux under /usr/share/dict/ directory, to check if the word is valid or it needs filtering.
I don't quite get what you are trying to do.
I ran into this same problem and solved it in the following way:
1) Have a google spreadsheet with all words that I want to filter out
2) Directly download the google spreadsheet into my code with the loadConfigs method (see below)
3) Replace all l33tsp33k characters with their respective alphabet letter
4) Replace all special characters but letters from the sentence
5) Run an algorithm that checks all the possible combinations of words within a string against the list efficiently, note that this part is key - you don't want to loop over your ENTIRE list every time to see if your word is in the list. In my case, I found every combination within the string input and checked it against a hashmap (O(1) runtime). This way the runtime grows relatively to the string input, not the list input.
6) Check if the word is not used in combination with a good word (e.g. bass contains *ss). This is also loaded through the spreadsheet
6) In our case we are also posting the filtered words to Slack, but you can remove that line obviously.
We are using this in our own games and it's working like a charm. Hope you guys enjoy.
https://pimdewitte.me/2016/05/28/filtering-combinations-of-bad-words-out-of-string-inputs/
public static HashMap<String, String[]> words = new HashMap<String, String[]>();
public static void loadConfigs() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new URL("https://docs.google.com/spreadsheets/d/1hIEi2YG3ydav1E06Bzf2mQbGZ12kh2fe4ISgLg_UBuM/export?format=csv").openConnection().getInputStream()));
String line = "";
int counter = 0;
while((line = reader.readLine()) != null) {
counter++;
String[] content = null;
try {
content = line.split(",");
if(content.length == 0) {
continue;
}
String word = content[0];
String[] ignore_in_combination_with_words = new String[]{};
if(content.length > 1) {
ignore_in_combination_with_words = content[1].split("_");
}
words.put(word.replaceAll(" ", ""), ignore_in_combination_with_words);
} catch(Exception e) {
e.printStackTrace();
}
}
System.out.println("Loaded " + counter + " words to filter out");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Iterates over a String input and checks whether a cuss word was found in a list, then checks if the word should be ignored (e.g. bass contains the word *ss).
* #param input
* #return
*/
public static ArrayList<String> badWordsFound(String input) {
if(input == null) {
return new ArrayList<>();
}
// remove leetspeak
input = input.replaceAll("1","i");
input = input.replaceAll("!","i");
input = input.replaceAll("3","e");
input = input.replaceAll("4","a");
input = input.replaceAll("#","a");
input = input.replaceAll("5","s");
input = input.replaceAll("7","t");
input = input.replaceAll("0","o");
ArrayList<String> badWords = new ArrayList<>();
input = input.toLowerCase().replaceAll("[^a-zA-Z]", "");
for(int i = 0; i < input.length(); i++) {
for(int fromIOffset = 1; fromIOffset < (input.length()+1 - i); fromIOffset++) {
String wordToCheck = input.substring(i, i + fromIOffset);
if(words.containsKey(wordToCheck)) {
// for example, if you want to say the word bass, that should be possible.
String[] ignoreCheck = words.get(wordToCheck);
boolean ignore = false;
for(int s = 0; s < ignoreCheck.length; s++ ) {
if(input.contains(ignoreCheck[s])) {
ignore = true;
break;
}
}
if(!ignore) {
badWords.add(wordToCheck);
}
}
}
}
for(String s: badWords) {
Server.getSlackManager().queue(s + " qualified as a bad word in a username");
}
return badWords;
}

Java: 2 runtime errors I can't figure out

I am working on a homework assignment, and I am going a little "above and beyond" what is called for by the assignment. I am getting a run-time error in my code, and can not for the life of me figure out what it is that I have done wrong.
Here is the assignment:
Write a program that displays a simulated paycheck. The program should ask the user to enter the date, the payee’s name, and the amount of the check. It should then display a simulated check with the dollar amount spelled out.
Here is my code:
CheckWriter:
/* CheckWriter.java */
// Imported Dependencies
import java.util.InputMismatchException;
import java.util.Scanner;
public class CheckWriter {
public static void main(String args[]) {
Scanner keyboard = new Scanner(System.in);
// Try to get the name
String name = "";
NameValidator validateName = new NameValidator();
while (validateName.validate(name) == false) {
System.out.println("Enter the name: ");
name = keyboard.nextLine();
if (validateName.validate(name) == false) {
System.out.println("Not a valid name.");
}
}
// Get the date
String date = "";
DateValidator validateDate = new DateValidator();
while (!validateDate.validate(date)) {
System.out.println("Enter the date (dd/mm/yyyy): ");
date = keyboard.nextLine();
if (!validateDate.validate(date)) {
System.out.println("Not a valid date.");
}
}
// Try to get the amount of the check
String checkAmount = "";
CurrencyValidator validateCurrency = new CurrencyValidator();
while (!validateCurrency.validate(checkAmount)) {
System.out.print("Enter the Check Amount (XX.XX): $");
checkAmount = keyboard.nextLine();
if (!validateCurrency.validate(checkAmount)) {
System.out.println("Not a valid check amount.");
}
}
String checkWords = checkToWords(checkAmount); // ERROR! (48)
System.out
.println("------------------------------------------------------\n"
+ "Date: "
+ date
+ "\n"
+ "Pay to the Order of: "
+ name
+ " $"
+ checkAmount
+ "\n"
+ checkWords
+ "\n"
+ "------------------------------------------------------\n");
}
private static String checkToWords(String checkAmount) {
/**
* Here I will use the string.split() method to separate out
* the integer and decimal portions of the checkAmount.
*/
String delimiter = "\\.\\$";
/* Remove any commas from checkAmount */
checkAmount.replace(",", "");
/* Split the checkAmount string into an array */
String[] splitAmount = checkAmount.split(delimiter);
/* Convert the integer portion of checkAmount to words */
NumberToWords intToWord = new NumberToWords();
long intPortion = Long.parseLong(splitAmount[0]); // ERROR! (84)
intToWord.convert(intPortion);
String intAmount = intToWord.getString() + " dollars";
/* Convert the decimal portion of checkAmount to words */
String decAmount = "";
long decPortion = Long.parseLong(splitAmount[1]);
if (decPortion != 0) {
NumberToWords decToWord = new NumberToWords();
decToWord.convert(Long.parseLong(splitAmount[1]));
decAmount = " and " + decToWord.getString() + " cents.";
}
return (intAmount + decAmount);
}
}
Note that I am using external class files to handle validation of the name, date, currency, and conversion from numbers to words. These class files all work as intended.
The error I am getting is:
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
at java.lang.Long.parseLong(Unknown Source)
at CheckWriter.checkToWords(CheckWriter.java:82)
at CheckWriter.main(CheckWriter.java:46)
I have commented the lines in my code that are causing the errors that I am experiencing.
Could someone please assist me in figuring where my code is going wrong? I can include the other class files if you feel that it would be needed.
EDIT: When I run the code, it asks for the name and date. Before asking for the check amount is when it throws the error.
EDIT 2: A huge thank you to cotton.m! Thanks to his advice, I have changed the while statements to look like this:
while(!validateDate.validate(date) && date == "")
This has now fixed my issue. It would appear that when validating data with a regex expression, an empty string will return true.
The String you are trying to parse in an empty length string.
My suggestion would be to
1) Check the value of checkAmount at the start of checkToWords - if it is blank there's your problem
2) Don't do that split. Just replace the $ like you did the , (I think this is your real problem)
Also you are going to have another issue in that 10000.00 is not a long. I see you are splitting out the . but is that really what you want?
It is NumberFormatException, the value in checkAmount (method parameter) is not a valid Number.
You need to set checkAmount=checkAmount.replace(",", "");
Otherwise checkAmount will still have , inside and causes NumberFormatExcpetion.
Your issue is with your delimiter regex, currently you are using \.\$ which will split on a literal . followed by a literal $. I'm assuming that what you are actually intending to do is to split on either a . or a $, so change your delimiter to one of the following:
String delimiter = "\\.|\\$"
or
String delimiter = "[\\.\\$]"
As your code is now, checkAmount.split(delimiter) is not actually successfully splitting the string anywhere, so Long.parseLong(splitAmount[0]) is equivalent to Long.parseLong(checkAmount).
It should be:
String delimiter = "[\\.\\$]";
and then you have to check that splitWord[i] is not empty.

Categories