Scanner help - Java - java

I was looking for a little help as I'm at my wits end on how to accomplish this.
The assignment is to read in a file that contains state names, the governor of that state and the compensation he gets.
Example of the file:
California Tim John $50,000 $78,890 $30,000
North Dakota John Jones $30,000 $40,000 $56,000
Washington Susan K. Bones $30,000 $40,000 $56,000
As you can see, a name can contain more than three words (including the middle initial)
The output I'm supposed to get is the presidents name followed by the total compensation..
Example of output:
Susan K. Bones $126,000
I've already written code that prints out the total compensation. But I'm stuck on reading the names. How do I ignore the state names which can contain at most two words and just take the governor's name?
Here is my code for the total compensation.
Also note: I have to use Scanner on this.
Scanner in = new Scanner(file);
in.nextLine();
do {
double totalCompensation = 0.0;
String readLine = in.nextLine();
readLine = readLine.replaceAll(",", "").replace("$", " ");
String presidentName = "";
Scanner readNumber = new Scanner(readLine);
while(readNumber.hasNext()) {
if (readNumber.hasNextDouble())
totalCompensation += readNumber.nextDouble();
else {
readNumber.next();
}
}
Another note: don't worry, I do have a while(in.hasNextLine()) to close the do loop, later on in my code. I just don't really want to paste in the whole thing.
Any hints would be welcome! Thanks!

If you KNOW ahead of time that you will only ever see US state names, you could have your code look for a state name first. Since you know what part is the state name and what part is the compensation, whatever is left must be the governor's name. There's only 50 states, so this isn't impossibly difficult.
If this is more generic and can be a city/country/whatever and not just a US, there's not a way to distinguish without a better separator character (or quotes to define the "state name" and "governor name".
EDIT: You mention that there is a further requirement that the "leader" name will be of the form "Firstname LastName" "Firstname M. Lastname" or "F. Middlename Lastname". NOW you have enough to solve the answer.
As you pull strings out with the scanner, put them in a list (or if you learned this datatype, a stack is more appropriate). Go through the list backwards. If the 2nd element is an initial, you know the name has three parts. If the 3rd element is an initial, you know the name has three parts. If neither is an initial, you know the name has two parts. Whatever is not the name of the leader is the name of the place.

My previous answer utterly failed to use Scanner, which was a stated requirement. As before, I am using the "New," "North," etc, prefix to delineate two word state names.
static String[] TWO_WORD_STATE_PREFIXES = new String[] {"New", "Rhode", "North", "West", "South"};
public static void scanLine(String line) {
Scanner s = new Scanner(line);
String stateName = s.next();
for (String prefix : TWO_WORD_STATE_PREFIXES)
if (stateName.equals(prefix))
stateName += " " + s.next();
String governorName = "";
String nextToken;
while (!(nextToken = s.next()).startsWith("$"))
governorName += nextToken + " ";
governorName = governorName.trim();
int compensation = 0;
while (s.hasNext())
compensation += Integer.parseInt(s.next().replaceAll("[\\$, ]", ""));
System.out.println(stateName + " - " + governorName + " : " + compensation);
}
public static void main(String[] args) {
scanLine("California Tim John $50,000 $78,890 $30,000");
scanLine("Virginia Some Guy $55,000 $71,890 $30,000");
scanLine("South Carolina Bill F. Gates $91,000 $1,200");
scanLine("Vermont Joan Smith $60,000 $78,890 $30,000");
scanLine("North Dakota Tim John $50,000 $78,890 $30,000");
}

Can the file be modified to contain delimiters other than space like semi-colon. Otherwise one option i can think of is store the list of states and iterate through them and check other wise it would be a name. Eg.
List<String> stateNames={"Alabama","Alaska","Texas"};

This question is about efficient string searching. Let's work on determining which part of the string is the city or state name, since once you have that the rest is trivial.
First, you will need a list of cities and states. Here's a list of cities (should be pretty easy to parse out the actual city names) http://www.census.gov/tiger/tms/gazetteer/places2k.txt and I'm sure you can find a list of states somewhere.
Once you have that, here's a simple strategy for an efficient solution:
put the list of cities and states into a hashtable
split the input string (ex. "Califonia John Doe $213 $1232") by spaces
for each prefix of this list, check if the corresponding string is in the hashtable - if it is, then assume that's the state/city and parse the rest of the input accordingly.
Edit: nevermind - you added some information to the question that makes it much easier to solve. It's no longer an efficient string search problem- it's now a simple puzzle to help you practice looping in Java. See Kane's answer.
It's interesting how drastically just a little bit of information can change the scope of a problem :)

Related

How do i print the the first initial of a string and the last word of a string?

How do I print only the first letter of the first word and the whole word of the last? for example,
I will request username input like "Enter your first and last name" and then if I type my name like "Peter Griffin", I want to print only "P and Griffin". I hope this question make sense. Please, help. I'm a complete beginner as you can tell.
Here is my code:
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
System.out.println("Enter your first and last name");
String fname=scan.next();
}
The String methods trim, substring, indexof, lastindexof, and maybe split should get you going.
This should do the work (typed directly here, so syntax errors might be there)
String fname=scan.nextLine(); // or however you would read whole line
String parts=fname.split(" ");
System.out.printf("%s %s",parts[0].substring(0,1),parts[parts.length-1]);
What you have to do next:
Check if there actually at least 2 elements in parts array
Check if first element is actually at least 1 char (no empty parts)
Check if there is actually line to read
Do your next homework yourself, otherwise you will not anything
I recommand you to watch subString(1, x) and indexOf(" ") to cut from index 1 to first space.
or here a other exemple, dealing with lower and multi name :
String s = "peter griffin foobar";
String[] splitted = s.toLowerCase().split(" ");
StringBuilder results = new StringBuilder();
results.append(String.valueOf(splitted[0].charAt(0)).toUpperCase() + " ");
for (int i = 1; i < splitted.length; i++) {
results.append(splitted[i].substring(0, 1).toUpperCase() + splitted[i].substring(1)+" ");
}
System.out.println(results.toString());

How to print part of a String from an array (Java)?

Hello im a total beginner in Java and have a problem. In a code below that has an array of fixed list of guests, how can i print emails of these person? The email must consist of 3 first name digits and two first surname digits, and after these are #guest.com. So it looks like this:
adaro#guest.com
thost#guest.com
In this task i must use methods: substring, split, toLowerCase.
Sorry for my english its not perfect. Please help i've tried to solve this but i'm stuck cant manage it.
public class email {
public static void main(String[] args) {
String[] guests = { "Rock Adam",
"Stewart Thomas",
"Anderson Michael",
};
}
}
When you are stuck like this, try breaking down the problem bit by bit.
You are saying you don't know how to extract part of string, but also how to print. I'm tempted to give you written instructions and not the full answer to your question because that's how you will learn better.
You need to construct this email for each String in the String[] array. Look for iterating over arrays in java here for example https://www.geeksforgeeks.org/iterating-arrays-java/
For each String which is of this form "Rock Adam" you need to extract the surname and last name. To do this you need to split the String by space " ". How to do that - How to split a String by space
When you split by space you will get another Array of two elements, first will be surname, second will be first name. Use array indecies to access them.
When you access the firstName your next problem is - how do I get the first 3 characters of that String. How to access 3rd or 2nd is the same problem see how to do this here Extract first two characters of a String in Java
Now that you have the substrings you want to know how to concatenate and print them. How to print multiple variables? Answer is here How to print multiple variable lines in Java. Also for transforming the strings to lowercase you can find answer here https://www.w3schools.com/java/ref_string_tolowercase.asp
Try to do some more work yourself following this and you will learn much more than from copy-pasting what someone will give you directly for free.
Lower code solves your problem. String.split(" ") splits the String at the first occurrence of blank space. It gives a String array back which contains both parts of the name. With String.substring() you can get specific parts of the String.
public static void main(String[] args) {
String[] guests = {"Rock Adam",
"Stewart Thomas",
"Anderson Michael"};
for(String guest : guests){
String[] name = guest.split(" ");
String email = name[1].substring(0,3).toLowerCase() + name[0].substring(0,2).toLowerCase() + "#guest.com";
System.out.println(email);
}
}
Below code is exactly what you are looking for (i guess)
String[] guests = { "Rock Adam",
"Stewart Thomas",
"Anderson Michael",
};
List<String> emailIdList = new ArrayList<>();
for (String guest : guests) {
String firstName = guest.split(" ")[1];
String lastName = guest.split(" ")[0];
String emailId = firstName.substring(0,2) + lastName.substring(0,1) + "#guest.com";
emailIdList.add(emailId);
}

Java - How to Delimit Single Quotes Around a Phrase but Not an Apostrophe in a Word

I am practicing Java on my own from a book. I read the chapter on text processing and wrapper classes and attempted the excercise below.
Word Counter
Write a program that asks the user for the name of a file. The program should display the number of words that the file contains.
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.StringTokenizer;
public class FileWordCounter {
public static void main(String[] args) throws IOException {
// Create a Scanner object
Scanner keyboard = new Scanner(System.in);
// Ask user for filename
System.out.print("Enter the name of a file: ");
String filename = keyboard.nextLine();
// Open file for reading
File file = new File(filename);
Scanner inputFile = new Scanner(file);
int words = 0;
String word = "";
while (inputFile.hasNextLine()) {
String line = inputFile.nextLine();
System.out.println(line); // for debugging
StringTokenizer stringTokenizer = new StringTokenizer(line, " \n.!?;,()"); // Create a StringTokenizer object and use the current line contents and delimiters as parameters
while (stringTokenizer.hasMoreTokens()) { // for each line do this
word = stringTokenizer.nextToken();
System.out.println(word); // for debugging
words++;
}
System.out.println("Line contains " + words + " words");
}
// Close file
inputFile.close();
System.out.println("The file has " + words + " words.");
}
}
I chose this random poem from online to test this program. I put the poem in a file called TheSniper.txt:
Two hundred yards away he saw his head;
He raised his rifle, took quick aim and shot him.
Two hundred yards away the man dropped dead;
With bright exulting eye he turned and said,
'By Jove, I got him!'
And he was jubilant; had he not won
The meed of praise his comrades haste to pay?
He smiled; he could not see what he had done;
The dead man lay two hundred yards away.
He could not see the dead, reproachful eyes,
The youthful face which Death had not defiled
But had transfigured when he claimed his prize.
Had he seen this perhaps he had not smiled.
He could not see the woman as she wept
To the news two hundred miles away,
Or through his very dream she would have crept.
And into all his thoughts by night and day.
Two hundred yards away, and, bending o'er
A body in a trench, rough men proclaim
Sadly, that Fritz, the merry is no more.
(Or shall we call him Jack? It's all the same.)
Here is some of my output...
For debugging purposes, I print out each line and the total words in the file up including those in the current line.
Enter the name of a file: TheSniper.txt
Two hundred yards away he saw his head;
Two
hundred
yards
away
he
saw
his
head
Line contains 8 words
He raised his rifle, took quick aim and shot him.
He
raised
his
rifle
took
quick
aim
and
shot
him
Line contains 18 words
...
At the end, my program displays that the poem has 176 words. However, Microsoft Word counts 174 words. I see from printing each word that I am miscounting apostrophes and single quotes. Here is the last section of the poem in my output where the problem occurs:
(Or shall we call him Jack? It's all the same.)
Or
shall
we
call
him
Jack
It
s
all
the
same
Line contains 176 words
The file has 176 words
In my StringTokenizer parameter list, when I don't delimit a single quote, which looks like an apostrophe, the word "It's" is counted as one. However, when I do, its counted as two words (It and s) because the apostrophe, which looks like a single quote, gets delimited. Also, the phrase 'By Jove, I got him!' is miscounted when I don't delimit the single quote/apostrophe. Are the apostrophe and single quote the same character when it comes to delimiting them?? I'm not sure how to delimit single quotes that surround a phrase but not an apostrophe between a word like "It's". I hope I am somewhat clear in asking my question. Please ask for any clarifications. Any guidance is appreciated. Thank you!
Why not use another Scanner for each line to count the number of words?
int words = 0;
while (inputFile.hasNextLine()) {
int lineLength = 0;
Scanner lineScanner = new Scanner(inputFile.nextLine());
while (lineScanner.hasNext()) {
System.out.println(lineScanner.next());
lineLength++;
}
System.out.println("Line contains " + lineLength + " words");
words += lineLength;
}
I don't believe it is possible to delimit a single quote for a phrase like "'By Jove, I got him!'", but ignore it in "it's" unless you use a regex search to ignore single quotes in the middle of a word.
Alternatively, you could treat the characters ".!?;,()" as part of a single word (eg. "Jack?" is one word), which will give you the correct word count. This is what the scanner does. Just change the delimiter in your StringTokenizer to " " (\n isn't required since you're already searching each line):
StringTokenizer stringTokenizer = new StringTokenizer(line, " ");

Why do i get a "terminated due to timeout" error for my code at hackerrank?

I got a "Terminated due to timeout error" when i ran my code for some specific testcases only. Even though my code compiled successfully for other testcases. Can someone please help me with this?
Link - https://www.hackerrank.com/challenges/phone-book
Problem Statement :
You are given a phone book that consists of people's names and their phone number. After that you will be given some person's name as query. For each query, print the phone number of that person.
Input Format :
The first line will have an integer denoting the number of entries in the phone book. Each entry consists of two lines: a name and the corresponding phone number.
After these, there will be some queries. Each query will contain a person's name. Read the queries until end-of-file.
Constraints:
1<=n<=100000
1<=Query<=100000
A person's name consists of only lower-case English letters and it may be in the format 'first-name last-name' or in the format 'first-name'. Each phone number has exactly 8 digits without any leading zeros.
Output Format :
For each case, print "Not found" if the person has no entry in the phone book. Otherwise, print the person's name and phone number. See sample output for the exact format.
To make the problem easier, we provided a portion of the code in the editor. You can either complete that code or write completely on your own.
My code is as follows :
import java.util.*;
import java.io.*;
class Solution
{
public static void main(String []args)
{
Scanner in = new Scanner(System.in);
int n=in.nextInt();
in.nextLine();
ArrayList<String> name = new ArrayList<String>();
int[] phone = new int[100000];
for(int i=0;i<n;i++)
{
name.add(in.nextLine());
phone[i]=in.nextInt();
in.nextLine();
}
while(in.hasNext())
{
String s=in.nextLine();
int a=name.indexOf(s);
if(a>=0)
{
System.out.println(s + "=" + phone[a] );
}
else
{
System.out.println("Not found");
}
}
}
}
PS:This is my first question on the forum. I'm an amateur learning java. Sorry if i violated any of the many rules of asking a question :( . Please do correct me and help me contribute to the community here in a good way :)
The problem with your logic is that it is implemented using ArrayList which is a sequential structure. Any search in List will be sequential and for large test cases its taking too much time to lookup in your names list.
Hash map is more appropriate for a phone book example as it keeps data in key, value pair and look ups are fast because of hashing
Here is a version that is implemented using HashMap
Map<String,Integer> phonebook = new HashMap<>();
Scanner in = new Scanner(System.in);
int n=in.nextInt();
in.nextLine();
for(int i=0;i<n;i++)
{
String name=in.nextLine();
int phone=in.nextInt();
in.nextLine();
phonebook.put(name,phone);
}
while(in.hasNext())
{
String s=in.nextLine();
Integer phone = phonebook.get(s);
if(phone==null){
System.out.println("Not found");
} else {
System.out.println(s+"="+phone);
}
}
Hope this explains.
Usually "Terminated due to timeout error" occurs when your code takes longer time to execute than the maximum time set by the Problem Setters(Hackerrank).
The problem you tried is intended to teach you how HashMaps are used, but you solved the problem using arrays. Searching in arrays takes O(n)longer time than that of Maps which are generally hashed to search in O(1) time. For smaller input your program works fine, but for larger inputs like 100000 entries, It will take longer time and result in time out. So Use Maps instead of Arrays and ArrayLists

Profanity filter

So far I have been able to censor "cat", "dog" and "llama". Now I just need to make the exception of "Dogmatic" but cannot figure it out for the life of me. Below I have attached what I have so far. Please any suggestions will help really.
/* take userinput and determine if it contains profanity
* if userinput contains profanity, it will be filtered
* and a new sentence will be generated with the word censored
*/
keyboard = new Scanner(System.in);
System.out.println("Welcome to the Star Bulletin Board!");
System.out.println("Generate your first post below!");
String userInput = keyboard.nextLine();
userInput = userInput.toLowerCase();
if (userInput.indexOf("cat") != 15){
System.out.println("Your post contains profanity.");
System.out.println("I have altered your post to appear as: ");
System.out.println(userInput.replaceAll("cat", "***"));
}
else
System.out.println(userInput);
if (userInput.indexOf("dog") != -1){
System.out.println("Your post contains profanity.");
System.out.println("I have altered your post to appear as: ");
System.out.println(userInput.replaceAll("dog", "***"));
}
if (userInput.indexOf("llama")!= -1){
System.out.println("Your post contains profanity.");
System.out.println("I have altered your post to appear as: ");
System.out.println(userInput.replaceAll("llama", "*****"));
}
You can use a word boundary \\b. Word boundaries match the edges of a word, like spaces or punctuation.
if (userInput.matches(".*\\bdog\\b.*")) {
userInput = userInput.replaceAll("\\bdog\\b", "***");
}
This will censor "Don't be a llama." but it won't censor "Don't be dogmatic."
userInput.matches(".*\\bdog\\b.*") is a slightly better condition than indexOf/contains because it has the same match as the replacement. indexOf/contains would still show the message despite not censoring anything. .* matches any character (except typically new lines), optionally.
Note: this is still not a very effective way to filter profanity. See http://blog.codinghorror.com/obscenity-filters-bad-idea-or-incredibly-intercoursing-bad-idea/.
Use word boundaries. Take a look at the following code; it will print true for all cases except the last one:
String a = "what you there";
String b = "yes what there";
String c = "yes there what";
String d = "whatabout this";
System.out.println(Pattern.compile("\\bwhat\\b").matcher(a).find());
System.out.println(Pattern.compile("\\bwhat\\b").matcher(b).find());
System.out.println(Pattern.compile("\\bwhat\\b").matcher(c).find());
System.out.println(Pattern.compile("\\bwhat\\b").matcher(d).find());
You can combine all your bad words into a single regex like so:
Pattern filter = Pattern.compile("\\b(cat|llama|dog)\\b");
This is fine for simple cases, but for a more robust solution you probably want to use a library. Take a look at this question for more information.

Categories

Resources