returning string containing char c in scanner - java

Trying to create a method findNewLineWithChar() which returns a String and accepts a Scanner scn and a char c. It returns the line of the scanner which contains c.
I've tried using a string to store the value of currentLine, but it seemed to convolute my code and not provide any answers anyways. I would love to use a String[], but I get a NullPointerException. What am I exactly doing wrong?
public static String findLineWithChar(Scanner scn, char c) {
/*
* findLineWithChar returns line in scanner if line has char c
* #param scanner
* #param c
*/
String result = "";
String[] stringArray = new String[10]; //accepts max 10 lines
int counter = 0; //populate string array from scn
while(scn.hasNextLine()) {
stringArray[counter] = scn.nextLine();
counter++;
}
//iterate through each element in string array
for (int i = 0; i < 10; i++) {
if (stringArray[i].contains(c + "")) {
result = stringArray[i];
System.out.println(stringArray[i]);
break;
} else {
result = "";
}
}
return result;
}
It works if I feed it a true statement,
findLineWithChar(new Scanner("Look here!\nLook there!\nExtra extra!"), 'x') returns Extra extra!, but findLineWithChar(new Scanner("Look here!\nLook there!\nExtra extra!"), 'q') returns a NullPointerException. How do I deal with this?

First, Javadoc comments go before the method (and start with /**). Second, you don't need an array here; just keep a count to make sure you don't consume more than ten lines (assuming that's necessary). Instead of setting a return variable and breaking the loop, I would return when a matching line is found. I would also prefer String.indexOf(int) to building one character String(s) for comparison. And, add a default return value for when nothing matches. Like,
/**
* findLineWithChar returns line in scanner if line has char c
*
* #param scanner
*
* #param c
*/
public static String findLineWithChar(Scanner scn, char c) {
int counter = 0;
while (scn.hasNextLine() && counter < 10) {
String line = scn.nextLine();
if (line.indexOf(c) > -1) {
return line;
}
counter++;
}
return "";
}

You almost got it! Just change condition of your while loop.
from this:
while(scn.hasNextLine()) {
to this:
while(scn.hasNextLine() && counter < 10) {

Related

Trying to alternate two strings together in Java

/* Programs goal is to take two strings and use a method to alternate the characters.
example - "test" "case" -> "tceasste"
Sorry I tried looking at other similar questions but I didn't understand how they worked as I am very new to Java and coding in general.
*/
public class MyProgram extends ConsoleProgram
{
public void run()
{
System.out.println(sCombine("test","case")); //"tceasste"
System.out.println(sCombine("avalanche","dog")); //"advoaglanche"
System.out.println(sCombine("","water")); //"water"
}
public String sCombine(String a, String b)
{
String result = "";
int lengtha = a.length();
int lengthb = b.length();
int lengthc = 0;
if(lengtha < lengthb)
{
lengthc = lengtha;
}
else
{
lengthc = lengthb;
}
for(int i = 0; i < lengthc; i++)
{
char currentA = a.charAt(i);
char currentB = b.charAt(i);
result += a;
result += b;
}
return result;
}
}
The problem is that you're doing:
result += a;
You need to do:
result += currentA;
I would also suggest looking at the StringBuilder class. It has a lot of built in functionality for things of this nature :)
Just another way. Read all the comments in code:
/**
* Sequentially blends two strings together one character at a time, for
* example, if the first argument was "cat" and the second argument was
* "dog" then the returned result will be: "cdaotg".<br><br>
*
* <b>Example Usage:</b><pre>
* {#code
* final String a = "cat";
* final String b = "elephant";
* String newString = sCombine(a, b);
* System.out.println(newString);
* // Console will display: cealte }
*
* OR
* {#code
* final String a = "cat";
* final String b = "elephant";
* String newString = sCombine(a, b, true); // true is optionally supplied here.
* System.out.println(newString);
* // Console will display: eclaetphant }</pre>
*
* #param stringA (String) The first String to blend.<br>
*
* #param stringB (String) The second String to blend.<br>
*
* #param startWithLongest (Optional - boolean varArgs) Default is false <pre>
* whereas this method will always take the first
* supplied argument and blend the second argument
* into it. In this default situation, the first
* argument is always considered to contain the
* longest String. If however, the second argument
* contains more characters then the those extra
* characters will be truncated, for example: "cat"
* and "elephant". Result will be: "cealte". It would
* be beneficial to always pass the longest string as
* the first argument in order to achieve the result
* of: "eclaetphant".
*
* If boolean true is supplied to this optional parameter
* then the longest argument passed to this method will
* always be considered as the first argument rather than
* the first supplied argument, for example: "cat" as the
* first argument and "elephant" as the second argument
* and true as the third argument will return a result
* of "eclaetphant".
*
* Supplying nothing forces default to be used.</pre>
*
* #return (String) The blended String;
*/
public static String sCombine(final String stringA, final String stringB,
final boolean... startWithLongest) {
String strgA = stringA, strgB = stringB; // So to maintain original Strings
/* If `true` is supplied to the startWithLongest optional
vararg parameter then ensure the String argument with the
most characters is the first argument (if true, always place
the longest first). */
if (startWithLongest.length > 0 && startWithLongest[0]) {
if (strgB.length() > strgA.length()) {
strgA = stringB;
strgB = stringA;
}
}
// Build the new blended string
StringBuilder sb = new StringBuilder("");
for (int i = 0; i < strgA.length(); i++) {
sb.append(strgA.charAt(i))
/* 'Ternary Operator' is used here to ensure strgB
contains the current index to carry on. If not
then just the remaining characters of strgA are
sequentially apended to the StringBuilder object
to finish up things. */
.append(i < strgB.length() ? strgB.charAt(i) : "");
}
return sb.toString();
}
You can use a loop that iterates the maximum length of both the strings. Then you can extract the individual character at the ith position and add it alternatively to a resulting String object. I have used StringBuiler as it mutable( diff here ) This is the code that I have attached.
public class MyProgram {
public static void main(String[] args) {
System.out.println(sCombine("test", "case")); // "tceasste"
System.out.println(sCombine("avalanche", "dog")); // "advoaglanche"
System.out.println(sCombine("", "water")); // "water"
}
public static String sCombine(String a, String b) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < Math.max(a.length(), b.length()); i++) {
char aChar = i < a.length() ? a.charAt(i) : '#';
char bChar = i < b.length() ? b.charAt(i) : '#';
if (aChar != '#') {
result.append(aChar + "");
}
if (bChar != '#') {
result.append(bChar + "");
}
}
return result.toString();
}
}
and the output is :
tceasste
advoaglanche
water
You can use substring to savely append the remainder of the Strings. Should the limit be out of bounds, no exception will be thrown, because substring will just return an empty String.
public String sCombine(String a, String b) {
final StringBuilder builder = new StringBuilder();
final int min = Math.min(a.length(), b.length());
for (int i = 0; i < min; i++) {
builder.append(a.charAt(i)).append(b.charAt(i));
}
builder.append(a.substring(min)).append(b.substring(min));
return builder.toString();
}
take two strings and use a method to alternate the characters.
example - "test" "case" -> "tceasste"
private static String mixedUp(String first, String second)
{
First, identify the shorter string so it won't attempt to pull a character that is out out bounds
int length = (first.length() > second.length())
? second.length() : first.length();
Then for that length, add their alternating characters to a new String() Object like so:
String output = new String();
for(int index = 0; index < length; index++)
{
output += first.charAt(index);
output += second.charAt(index);
}
You can use substring to savely append the remainder of the Strings. Should the limit be out of bounds, no exception will be thrown, because substring will just return an empty String. - #thinkgruen
You can add the rest of the characters using the ternary operator again like so:
output += (first.length() > second.length())
? second.substring(length) : first.substring(length);
return output;
}

Need to encode repetitive pattern in String with * , such that * means "repeat from beginning"

Encoding format: introduce * to indicate "repeat from beginning". Example. Input-{a,b,a,b,c,a,b,a,b,c,d} can be written as {a , b, * ,c, * , d}. Output:5; E.g 2: ABCABCE, output- 5.
Here * means repeat from beginning. For example if given String is ABCABCABCABC , it will return ABC**, another example is if String is ABCABCABC, it will return ABC*ABC.
I have the below code but this code assumes that the string will contain the repetitive pattern only and no other characters, I want to modify it to check :
1. Which pattern is repeating
2. Ignore non repeating patterns
2. encode that pattern according to the problem statement
import java.util.Scanner;
public class Magicpotion {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the string:");
String str = sc.nextLine();
int len = str.length();
if (len != 0) {
int lenby3 = len / 3;
int starcount = ( int).(Math.log(lenby3) / Math.log(2));
int leftstring = (lenby3 - (int) Math.pow(2, starcount));
int resultlen = (1 * 3) + starcount + (leftstring * 3);
System.out.println("ResultLength: " + resultlen);
System.out.print("ABC");
for (int i = 0; i < starcount; i++) {
System.out.print("*");
}
for (int i = 0; i < leftstring; i++) {
System.out.print("ABC");
}
} else
System.out.println("ResultLength: " + 0);
}
}
Here my assumption is that ABC will always be repeating pattern , hence I have divided the length by 3. I want to generalise it such that I find the repeating pattern which can be a AB or BC or ABCD and proceed accordingly.
This looks like homework. So instead of a full solution just some hints:
You can process the input string character by character and encode as you go. If you have at some point already read k characters and the next k characters are exactly the same, output a * and advance to position 2k.
Otherwise, output the next input character and advance position to k+1.
As mentioned by dyukha this algorithm does not always result in the shortest possible encoding. If this is required some more effort has to be put into the search.
This problem can be solved using dynamic programming.
Assume that you processed your stay at some position i. You want to understand what it the minimal length of encoding of str[0..i]. Let's call it ans[i]. You have two options:
Just add i-th character to the encoding. So the length is ans[i-1] + 1.
You may write *, when possible. In this case the length is ans[i / 2] + 1 or something like this.
The final length is in ans[n-1]. You can store how you obtained ans[i] to recover the encoding itself.
Checking whether you can write * can be optimized, using some hashing (to obtain O(n) solution instead of O(n^2)).
The difference with Henry's solution is that he always applies * when it's possible. It's not clear to me that it results into the minimal length (if I understood correctly, aaaaaa is a counterexample), so I'm giving a solution I'm sure about.
/**
* #author mohamed ali
* https://www.linkedin.com/in/oo0shaheen0oo/
*/
public class Magic_potion_encoding
{
private static int minimalSteps( String ingredients )
{
StringBuilder sb = new StringBuilder(ingredients);
for(int i =0;i<sb.length();i++)
{
char startChar = sb.charAt(i);
int walkingIndex1=i;
int startIndex2 =sb.toString().indexOf(startChar,i+1);
int walkingIndex2=startIndex2;
while(walkingIndex2 !=-1 && walkingIndex2<sb.length() && sb.charAt(walkingIndex1) == sb.charAt(walkingIndex2) )
{
if(walkingIndex1+1==startIndex2)
{
String subStringToBeEncoded = sb.substring(i,walkingIndex2+1);//substring the string found and the original "substring does not include the last index hence the +1
int matchStartIndex = sb.indexOf(subStringToBeEncoded,walkingIndex2+1);// look for first match for the whole string matched
int matchEndeIndex= matchStartIndex+subStringToBeEncoded.length();
int origStartIndex=i;
int origEndIndex = i+subStringToBeEncoded.length();
if (matchStartIndex!=-1 )
{
if(origEndIndex==matchStartIndex)
{
sb.replace(matchStartIndex,matchEndeIndex,"*");
}
else
{
while(matchStartIndex!=-1 && matchEndeIndex<sb.length() && sb.charAt(origEndIndex) == sb.charAt(matchEndeIndex) )
{
if(origEndIndex==matchStartIndex-1)// if the index of the 2 strings are right behind one another
{
sb.replace(matchStartIndex,matchEndeIndex+1,"*");
}
else
{
origEndIndex++;
matchEndeIndex++;
}
}
}
}
sb.replace(startIndex2,walkingIndex2+1,"*");
break;
}
walkingIndex1++;
walkingIndex2++;
}
}
System.out.println("orig= " + ingredients + " encoded = " + sb);
return sb.length();
}
public static void main( String[] args )
{
if ( minimalSteps("ABCABCE") == 5 &&
minimalSteps("ABCABCEA") == 6 &&
minimalSteps("abbbbabbbb") == 5 &&
minimalSteps("abcde") == 5 &&
minimalSteps("abcbcbcbcd") == 6 &&
minimalSteps("ababcababce") == 6 &&
minimalSteps("ababababxx") == 6 &&
minimalSteps("aabbccbbccaabbccbbcc") == 8)
{
System.out.println( "Pass" );
}
else
{
System.out.println( "Fail" );
}
}
}
Given that the repetitions are from the beginning, every such repeating substring will have the very first character of the given string. [Every repetition needs to be represented by a "star". (i.e ABCABCABC ans = ABC** ) . If all sequential repetitions are to be represented with one "star". (i.e ABCABCABC and = ABC* ), a slight modification to (2) will do the thing (i.e remove the if case where the just a star is added)]
Divide the given string to substrings based on the first character.
Eg. Given String = "ABABCABD"
Sub Strings = {"AB", "ABC", "AB", "ABD"}
Just traverse through the list of substrings and get the required result. I've used a map here, to make the search easy.
Just a rough write up.
SS = {"AB", "ABC", "AB", "ABD"};
result = SS[0];
Map<string, bool> map;
map.put(SS[0],true);
for (i = 1; i < SS.length; i++){
if (map.hasKey(SS[i])){
result += "*";
}
else {
res = nonRepeatingPart(SS[i], map);
result += "*" + res;
map.put(SS[i], true);
}
}
String nonRepeatingPart(str, map){
for (j = str.length-1; j >= 0; j--){
if (map.hasKey(str.subString(0, j))){
return str.subString(j, str.length-1);
}
}
return throwException("Wrong Input");
}
string getCompressed(string str){
string res;
res += str[0];
int i=1;
while(i<str.size()){
//check if current char is the first char in res
char curr = str[i];
if(res[0]==curr){
if(str.substr(0,i)==str.substr(i,i)){
res += '*';
i+=i; continue;
}else{
res += curr;
i++; continue;
}
}else {
res += curr;
i++; continue;
}
}
return res;
}
int main()
{
string s = "ABCABCABC";
string res = getCompressed(s);
cout<<res.size();
return 0;
}

How to store all values from 100 to "User Input" in an array

When I'm done with this program it is suppose to display all palindromes and all prime palindromes that are greater than 100 and less than the number input by the user. As I'm going along in this assignment, I'm getting confused on how to store those values into the array that I have created "char[] charUser"
public static void main(String[] args)
{
Scanner promptUser = new Scanner(System.in);
System.out.print("Enter an Integer greater than 100: ");
Integer userInt = new Integer(promptUser.nextInt());
String userString = userInt.toString();
char[] charUser = userString.toCharArray();
if (userInt <= 100)
{
System.out.print("That integer is not greater than 100,"
+ " restart program and try again!");
}
char[] resultArray = reverseArray(charUser);
for(int i = 0; i < resultArray.length; i++)
{
System.out.print(resultArray[i]);
}
}
/**Takes the integer provided by the user and turns it into a string
* then takes that string and puts it into a char[], then there is a for loop
* to reverse that array.
* #param charUser array used to store the reversed string.
* #revArray char array used to store data from charChange array.
* #return returns charChange now with the reversed string.
*/
public static char[] reverseArray(char[] charUser)
{
char[] revArray = new char[charUser.length];
for(int i = 0; i < revArray.length; i++)
{
revArray[i] = charUser[charUser.length - 1 - i];
}
return revArray;
}
/** Takes the original array charUser before being reversed and
* compares it with the reversed array resultArray to determine if they
* are equal.
* #param charUser original array created from the user input.
* #param resultArray the reversed array of charUser.
* #return returns the answer to boolean isPalindrome, whether or not the
* two arrays are equal.
*/
public static boolean arraysAreEqual(char[] charUser, char[] resultArray)
{
char[] isPal1 = new char[charUser.length];
char[] isPal2 = new char[resultArray.length];
boolean isPalindrome = false;
if(isPal1[isPal1.length] == isPal2[isPal2.length])
{
isPalindrome = true;
}
return isPalindrome;
}
public static boolean isPrime(int userInt)
{
int intUser = userInt;
boolean checkPrime = true;
for(int i = 2; i < Math.sqrt(intUser); i++)
{
if(intUser % i == 0)
return false;
}
return checkPrime;
}
/*public void printArray(char[] resultArray)
{
}*/
}
If you want to use an array, you need to know exactly the length of the array (how many elements you want that array to contain) using this line:
int[] palindrome = new int[x]; //x being the length of the array
However if you need to add your new found palindromes to an array in a dynamic fashion (on the fly) you need to use the Arraylist class.
An Arraylist would be initialized like this:
Arraylist<Integer> palindromes = new Arraylist<Integer>();
ANd then elements can be added whenever you find a new plalindrome with the add method of the Arraylist class:
palindromes.add(x); //x being the number to add to the list
You should take a look at Oracle's documentation here for more info on Arraylist and it's many methods
Hope this helps
EDIT
To answer your question you need to rethink this method completely:
public static boolean arraysAreEqual(char[] charUser, char[] resultArray)
{
char[] isPal1 = new char[charUser.length];
char[] isPal2 = new char[resultArray.length];
boolean isPalindrome = false;
if(isPal1[isPal1.length] == isPal2[isPal2.length])
{
isPalindrome = true;
}
return isPalindrome;
}
If you want to create a new char array (as a copy of the one passed as a parameter) you can't do it the way you did it. Altought you wouldn't even need to create a new array, you could just used the one passed as a parameter.
Next point if you want to compare the char array with it's opposite array, you need to loop and check elements by elements. If you convert them to int you can just check easily if they are equal:
if (number == oppositeNumber){
//it is a palindrome
//Therefor return true
}
return false; (if it isn't a palindrome return false)
How to cast char array to int
If you want to convert your char array to an int you need to do these simple steps:
Cast char array to String
Cast String to int
Like this examples shows:
char[] nums = {'1','2','2','1'};
String str = String.valueOf(nums);
int number = Integer.parseInt(str);
System.out.println(number);

changing a string of numbers into an int from a part of a parsed string

So if I were given a string "Cylinder/soda200/0.0054/5/10" and were to parse it, how would I actually take the parts with just numbers and turn them into an int or double?
Currently I am parsing it by doing this:
String delims="[/]+";
String[] drinkParse=lineToParse.split(delims);
Use Integer.parseInt(), Double.parseDouble() etc, passing your string as an argument.
e.g. int i = Integer.parseInt(drinkParse[3]);
Note that these can throw a NumberFormatException if the argument can't be parsed as requested. (e.g. "soda200" can't parse straight to an int)
You can use new Integer("22") and save it to an int in order to convert it. Same for Double. There are other ways too though, I suggest simple googling.
You should use split function and parse like this
Object[] values = (Object[]) var.split("/");
values[2]=Double.parseDouble(values[2]);
values[3]=Integer.parseInt(values[3]);
values[4]=Integer.parseInt(values[4]);
System.out.println(values);
You can also iterate array and check if string validates against rege/p of double or int and then do corresponding conversion if you dont know positions.
I'm not sure if you're familiar with StringBuilder in java, but you can learn more about it here and you can also take a look at String API here. In the program example below I'm reading character by character from the string you posted until program runs into '/' or unless it's the end of the string. All characters are saved to the StringBuilder and converted into a String after to check if it's a number, either double or integer. If any character in the string is not a number or period isNumber flag value is set to false and we don't print it. In case it's a period we set isDouble flag value to true because we need that information for further conversion. At last we print the numbers if all conditions are true and create new StringBuilder in order to start building a fresh new String.
public class myProject {
public static void main(String[] args) {
String str = "Cylinder/soda200/0.0054/5/10";
StringBuilder sb = new StringBuilder();
boolean isDouble;
boolean isNumber;
System.out.println("List of numbers:");
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) != '/') {
sb.append(str.charAt(i));
}
if (str.charAt(i) == '/' || i+1 == str.length()) {
String strConvert = sb.toString();
isDouble = false;
isNumber = true;
for (int j = 0; j < strConvert.length(); j++) {
if (!Character.isDigit(strConvert.charAt(j))) {
if (strConvert.charAt(j) == '.') {
isDouble = true;
} else {
isNumber = false;
}
}
}
if (isDouble && isNumber) {
System.out.println(Double.parseDouble(strConvert));
} else if (isNumber) {
System.out.println(Integer.parseInt(strConvert));
}
sb = new StringBuilder();
}
}
}
}
Hopefully this will help you or anyone else with similar problem!

Trouble remedying NullPointerException in Java - think it's an initializing issue but can't find it

I have perused numerous other solutions to NPEs, and I've tried to implement other suggestions, but none of them quite match up what I'm trying to do and it just leads to more eclipse errors. I have compiled and tried to run from the command line, giving the application I'm running a couple strings when running at the command line. Below is the main class, and the class containing the methods that the main is using.
Class with the main method:
package my.package.ext;
public class WordCounterApp {
/**
* #param args
* Two command line arguments: the first one needs to be in quotes, the string that will be used, the second optional argument
* is the unique word to be counted (countWord method).
* #param source
* #param word
*/
public static void main(String[] args) {
String source = null;
String uniqueword = null;
StringBuilder word = null;
WordCounter counter = new WordCounter(source, word);
WordCounter uniqueCounter = new WordCounter(source, uniqueword);
counter.countWords(source);
counter.countUniqueWords(source);
uniqueCounter.countWord(source, uniqueword);
}
}
Class with the other methods:
package my.package.ext;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.Character;
import java.lang.StringBuilder;
public class WordCounter {
public Integer counter = 0;
public String source;
public HashSet<String> hashset;
public StringBuilder word;
public String uniqueword;
public WordCounter(String source) {
counter = new Integer(counter);
}
public WordCounter(String source, StringBuilder word) {
counter = new Integer(counter);
}
public WordCounter(String source, String uniqueword) {
counter = new Integer(counter);
}
/**
*
* #param line - the string parameter to get a total word count from.
*/
public int countWords(String source) {
boolean word = false;
int endOfLine = source.length() - 1;
Integer counter = 0;
for (int i = 0; i < source.length(); i++) {
if (Character.isLetter(source.charAt(i)) == true && i != endOfLine) {
word = true;
//} else if (Character.charValue(line.charAt(i)) == "-" && i != endOfLine) {
// word = true;
} else if (Character.isLetter(source.charAt(i)) == false && word == true) {
counter++;
word = false;
} else if (Character.isLetter(source.charAt(i)) && i == endOfLine) {
counter++;
}
}
System.out.println(counter);
return counter;
}
/**
*
* #param line - the string parameter that we will return the unique word count from. Randy recommends a HashSet.
* Put it into a hashset. Hashsets don't allow duplicate elements. Then do a count.
*/
public int countUniqueWords(String line) {
hashset = new HashSet<String>();
word = new StringBuilder();
int endOfLine = line.length() - 1;
boolean isWord = false;
String stringWord = null;
Integer counter = 0;
for (int i = 0; i < line.length(); i++) {
if (Character.isLetter(line.charAt(i)) == true && i != endOfLine) {
//System.out.println(i);
word.append(line.charAt(i));
isWord = true;
} else if (Character.isLetter(line.charAt(i)) == false && isWord == true) {
counter++;
//System.out.println("Counter is: " + counter);
stringWord = word.toString();
//System.out.println("stringWord is now: " + stringWord);
hashset.add(stringWord);
//System.out.println(hashset);
word = new StringBuilder();
isWord = false;
} else if (Character.isLetter(line.charAt(i)) && i == endOfLine) {
counter++;
stringWord = word.toString();
hashset.add(stringWord);
}
}
//System.out.println(counter);
System.out.println("There are " + hashset.size() + " unique words in this string");
System.out.println("These are the unique words in the string: " + hashset);
return counter;
}
/**
*
* #param source - the string the word is to be counted from
* #param word - the word to be counted
*
*/
public void countWord(String source, String word) {
String str = source;
Pattern p = Pattern.compile("\\s"+word+"\\s");
Matcher m = p.matcher(str);
int count = 0;
while (m.find()) {
count++;
}
System.out.println("The word: " + "\"" + word + "\"" + " appears " + count + " times.");
}
}
I have identified the source of the NPE here:
public int countWords(String source) {
boolean word = false;
int endOfLine = source.length() - 1; //the source of the NPE is this line
Integer counter = 0;
So looking at that, I figure I'm not initializing source correctly. I have tried things like
WordCounter source = new WordCounter()
But every variant of this I try, bringing in the correct constructor, gives me other eclipse errors. I can't seem to get there, and I'm afraid I'm going down the wrong path. I probably have other screw ups in here as well. I'm also unsure of the correct way to run from the command line while passing in some strings as arguments to feed the methods. Thanks in advance
your sourceString in your main method is null and you are passing it as an argument to countWords method.
public static void main(String[] args) {
String source = null;// it is null here
..............
............
counter.countWords(source);// passing null here
thus in your countWords when you call
int endOfLine = source.length() - 1;
as your source is null it will throw NullPointerException.
initialize your string to get rid of NPE.
EDIT: if you want to pass source as a command line argument.
String source =args[0];
and pass the commandline arguments at runtime.
Your main method:
public static void main(String[] args) {
String source = null;
// ... a few lines
counter.countWords(source);
// ... more code
}
The resulting error:
public int countWords(String source) {
boolean word = false;
int endOfLine = source.length() - 1; //the source of the NPE is this line
Integer counter = 0;
}
happens because source is null.
You pass null as source and call source.length a bit later. That causes the NPE.
counter.countWords(source);
Here source String is null causing NPE.
In your main method, you assign source to be null. You never reassign it to anything else so, when you call counter.countWords(source) it is the equivalent of calling counter.countWords(null).
This means, when you get to the line in countWords() where it attempts to call source.length(), source is actually null thus causing a NullPointerException to be thrown. To avoid this, you must assign source to be something prior to calling that method.
Here's my version, based on your "manual line parsing" approach:
package forums;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class WordCounterApp {
private static void printUsage() {
System.out.println("usage: java -cp C:\\Java\\home\\classes forums.WordCounterApp <text> [targetWord]");
System.out.println(" <text> is a quoted string to be split into words.");
System.out.println(" optional [targetWord] to be counted seperately.");
}
/**
* #param args
* REQUIRED [0] text: a quoted string to be searched for words.
* OPTIONAL [1] targetWord: the word to be counted, if desired.
*/
public static void main(String[] args) {
if (args.length==0) {
printUsage();
return;
}
String text = args[0];
String targetWord = args.length>1 ? args[1] : null;
WordCount wordCount = new WordCount(text);
System.out.println();
// all words in this string
List<String> words = wordCount.all();
System.out.println("There are "+words.size()+" words in the string. That are:\n"+words);
System.out.println();
// unique words in this string
Set<String> uniqueWords = wordCount.unique();
System.out.println("There are "+uniqueWords.size()+" unique words in the string. They are:\n"+uniqueWords);
System.out.println();
// the number of occurrences of the target word in this string, if given
if (targetWord ! = null) {
int targetCount = wordCount.of(targetWord);
System.out.println("The word \""+targetWord+"\" appears "+targetCount+" times.");
System.out.println();
}
}
}
/**
* Counts the words on a line, in various ways.
*/
class WordCount
{
private final String _line;
public WordCount(String line) {
_line = line;
}
public List<String> all() {
final List<String> results = new ArrayList<String>(64); // just a guess at max word-count.
final Matcher matcher = Pattern.compile("\\w+").matcher(_line);
int count = 0;
while ( matcher.find() )
results.add(matcher.group());
return results;
}
/**
* Returns a set of the unique words in the line
*/
public Set<String> unique() {
final HashSet<String> results = new HashSet<String>();
final int lineLength = _line.length();
final int endOfLine = lineLength-1;
final StringBuilder wordBuffer = new StringBuilder(16); // just a guess at max-word-length
char ch;
boolean isInWord = false;
// foreach character in the line EXCEPT the last one:
for ( int i=0; i<endOfLine; ++i ) {
ch = _line.charAt(i);
if ( Character.isLetter(ch) ) {
// we're at the start or continuation of the current word.
wordBuffer.append(ch);
isInWord = true;
} else if ( isInWord ) {
// we're reached the end-of-word, or the end-of-the-line.
results.add(wordBuffer.toString());
wordBuffer.setLength(0); // clear the word-buffer.
isInWord = false;
}
}
// handle the last character in the line seperately, just to save
// testing for it everytime through the loop... and I personally
// think that the logic is easier to follow this way.
ch = _line.charAt(endOfLine);
if ( Character.isLetter(ch) )
wordBuffer.append(ch);
if ( wordBuffer.length() > 0 )
results.add(wordBuffer.toString());
return results;
}
/**
* Returns the number of occurences of the targetWord.
* #param targetWord - the word to be counted.
*/
public int of(String targetWord) {
final String regex = "\\s+"+targetWord+"\\s+";
final Matcher matcher = Pattern.compile(regex).matcher(_line);
int count = 0;
while ( matcher.find() )
++count;
return count;
}
}
If was doing this for myself the all method would just use String.split(String regex) (because it's more succinct); and then the unique method would start with the results of the all method, instead of "manually parsing" the words out of the line (again because it's much more succinct).
Also, if I was doing this for real I'd be inclined to have one frequencyTable method that returns a HashMap<String, int> containing "the frequency table" - i.e. a map of each distinct word to the number of times it occurs. This recipe is flexible (and therefore reusable) and tends to be more efficient because you typically parse a line once, and then repeatedly query the parse-results... and if you're only querying the result once then you really haven't lost anything except a few clockticks, and they come in billions these days.
City17Mogul,
I stopped reading at your main method, because I already found a show-stopper: You're not doing anything at all with args (the command-line arguments passed into the main method)... so your source, uniqueWord, and word variables are ALLWAYS null... and I presume that is the root cause of your NullPointerException's.
You might also want to google for: How to read a stacktrace... it's a skill new programmers must learn, and the skill is even portable between (almost all) modern languages.
The stacktrace would have told you exactly which line of code the NPE occurs on, and from there it's usually pretty easy to workout which variable(s) is/are null... especially if you use a debugger... just put a breakpoint on the offending line, rerun the program WITH THE SAME INPUTS, and examine the value of all variables on that line... one or more of them must be null.
Cheers. Keith.

Categories