I cant find what causes the Exception - java

I am a java noob as well as very new to this site so please bear with me here. If I do something wrong in posting this please let me know and I apologize in advance for anything I do happen to do or any bad grammar.
I need to write a custom CSV parser in java that does not separate commas inside quotations. I cannot use anything related to the CSV class.
1,2,3,4 -> 1 2 3 4
a,"b,c",d -> a b,c d
No matter what i try i always get an exception
import java.io.*;
import java.util.*;
public class csv
{
public static void main(String[] args)
{
File file = new File("csv.test");
BufferedReader buf = null;
try
{
buf = new BufferedReader(new FileReader(file));
String str;
while ((str = buf.readLine()) != null)
{
String[] values = null; // array for saving each split substr
int c1 = 0; // counter for current position in string
int c2 = 0; // counter for next space in array to save substr
int c3 = 0; // location of last comma or quotation for substring creation
int i = 0; // counter used later for printing
while (c1 <= str.length())
{
char x = str.charAt(c1);
String s = Character.toString(x);
if (c1 == str.length())
{
values[c2] = str.substring(c3, (c1 - 1));
}
else if (s == ",")
{
values[c2] = str.substring(c3, (c1 - 1));
c1++;
c2++;
c3++;
}
else if (s == "\"")
{
c1++;
c3 = c1;
while (s != "\"")
c1++;
values[c2] = str.substring(c3, (c1 - 1));
c1 = c1 + 2;
c2++;
c3 = c1;
}
else
{
c1++;
}
while (i < values.length)
System.out.println("\"" + values[i] + "\"");
}
}
}
catch (Exception e)
{
System.out.println("Error locating test file");
}
}
}
I have tried cutting out all logic and testing if it is file io related. that reads fine so im down to it being logic related. I looked it over and cannot find anything wrong with it. I even had a friend look it through and said it looked fine. Where is the exception thrown?

You are not initializing your values in this line String[] values = null; hence it will fail when you use it i.e. at list values[c2] = str.substring(c3, (c1 - 1));.
To resolve the issue, please initialize the values array with proper length e.g. String[] values = new String[SIZE];. Probably you need to use str.length() as SIZE of the array.
Also in your comparison else if (s == ","), you are comparing String using ==, which is incorrect. Instead, you can use x itself as else if (x == ',').
Edit: Your condition below will make c1 in increment indefinitely as you are not changing the value of str(x after correction as advised) anywhere.
Old condition:
while (s != "\"")
c1++;
After change as advised(still wrong as x is not changing within the while loop):
while (x != '"')
c1++;
Please correct the loop logic.

Not related to the concrete problem but instead of s == ",", you should do ",".equals(s), similar for other string equality checks.

This is not the cause of your exception, but it is obviously incorrect nonetheless:
while (s != "\"")
c1++;
It is incorrect for two reasons:
Since the c1++ doesn't alter the loop condition, this will loop for ever.
You are using == / != to compare strings when you should be using equals(...). You appear to have made this mistake in other places too.
To find out what is causing the exception, the first thing you should do is to print out the stacktrace. Add e.printStackTrace(); to the catch block.
Or better still, change it to just catch IOException. Catching Exception is a bad idea ... unless you are going to log / output the full stacktrace.

Related

java.lang.StringIndexOutOfBoundsException Error while reading Binary String

I have a long String with binary values. And i have a hash map that has the Binary digits as a key and char as a value. I have a function that supposed to read the binary string using 2 pointers and compare with hashmap and store the corresponding char in main.decodedTxt. However, im getting string out of bound exception for this. I don't know how to solve this. I'm getting exception on "String temp =" line. I have a picture link of the console output to see better picture.
public static void bitStringToText (String binText){
String bs = binText;
int from =0;
int to = 1;
while(bs != null){
String temp = bs.substring(from, to);
if (main.newMapDecoding.containsKey(temp)){
main.decodedTxt += main.newMapDecoding.get(temp);
from =to;
to = from +1;
} else {
to = to + 1;
}
}
}
Image of console exception is here
First of all there is no need to check if bs is null because no part of your code changes the value of bs. Your current code will cross the possible index of your binText at some point. It's better to loop just binText and check if you find something within it. After all you have to traverse the complete string anyways. Change your code as follows
public static void bitStringToText (String binText){
//no need to do this if you are not modifying the contents of binText
//String bs = binText;
int from =0;
int to = 1;
int size = binText.length();
String temp = "";
while(to <= size ){
temp = binText.substring(from, to);
if (main.newMapDecoding.containsKey(temp)){
main.decodedTxt += main.newMapDecoding.get(temp);
from =to;
to = from +1;
} else {
to = to + 1;
}
}
}
Hope it helps.
First, give it a try to practice debugging. It is an easy case. Either use run in debug mode (place break point on String temp = bs.substring(from, to); line) or print values of from and to before the same line. It will help to understand what is going on.
Solution:
If bs is not null you will always have StringIndexOutOfBoundsException. Because you are not checking if to is pointing to not existed index of bs String. Easiest example of the first one will be empty String: bs == "".
One of the solution could be to replace condition in while to while (to <= bs.length()).

Dealing with StringIndexOutOfBoundsException in if statement Java

I have a program that gets an input from the console. It checks what the input is then using 'if's it decides what to do. One section test to see what the first four letters of the string are, to see if it needs to deal with it, but not all of the strings are always 4 or more letters long. This means that if you type in something that is less than 4 letters long, it encounters an error, and quits. I can't put that section at the end, because at the end there is an else, which if the command is unknown, is called and something happens. Is there a way I can stop the error from occurring?
My code is:
if(input.equals("help")){
int commandsSize = commands.size();
for(int i = 0; i < commandsSize; i++) {
String value = commands.get(i);
System.out.println(value);
} else if((input.substring(0, 4)).equals("open")) {
...
}
You can check the size of the string the user inputs,
if (input.length() != 4) {
System.out.println("You must enter valid input");
// Probably do something here.
}
if(input.equals("help")){
int commandsSize = commands.size();
for(int i = 0; i < commandsSize; i++) {
String value = commands.get(i);
System.out.println(value);
}
} else if((input.substring(0, 3)).equals("open")) {
...
}
Your code is erroring out on the substring method because if the string is less than 4 characters, the method is going outside the bounds of the string (or the char array that makes up the string). You will also want to check that you string is not null before calling methods on the string object.
To have the same flow as you currently have, but to protect your code against the substring error and not being null, you can do this:
if(input != null && input.equals("help")){
//some code
} else if((input != null && input.length() >= 4) && (input.substring(0, 4)).equals("open")) {
//some code
}

Removing Characters within a string-Java

I keep getting an error with removing a character from within a string. I have tried everything that i could find on this site and nothing has worked. This is NOT a help post. Rather maybe an answer that explains why this shows up and how to fix it in case someone else encounters this issue. Without further a due, here is my code:
public JTextField Clean()
{
String Cleaner = TopField.getText();
Cleaner=Cleaner.toLowerCase();
int Length = Cleaner.length();
StringBuilder Combiner = new StringBuilder(Cleaner);
for (int x=0;x+1<Length;x++)
{
char c = Cleaner.charAt(x);
char c1 = Cleaner.charAt(x+1);
if(c==' ' && c1==' ')
{
Combiner.deleteCharAt(x);
Cleaner=Combiner.toString();
}
if(c!='a' && c=='b' && c!='c' && c!='d' && c!='f' && c!='g' && c!='h' && c!='i' && c!='j' && c!='k' && c!='l' && c!='m' && c!='n' && c!='o' && c!='p' && c!='q' && c!='r' && c!='s' && c!='t' && c!='u' && c!='v' && c!='w' && c!='x' && c!='y' && c!='z' && c!=' ')
{Combiner.deleteCharAt(x);
Cleaner=Combiner.toString();}
}
TopField.setText(Cleaner);
return TopField;
}
I receive an error that states that My value is out of bounds by the length of the string that i input. Please note that this is a method inside a class that i created that removes any character that is not an alphabet or space.
Thanks in advance
As you remove characters, Cleaner becomes shorter, so you're likely to reach a point where x is too large.
I would suggest a different approach using regular expressions:
string cleaned = TopField.getText().toLowerCase().replaceAll("[^a-z ]", "");
There are a number of things that pop out at me.
Your basing your loop on a fixed value (Length), but where the actual length of the String can decrease...
You are potentially removing 2 characters per loop (there are two deleteCharAt calls)
The loop doesn't take into account the shrinking size of the String. For example. x == 1, you remove the character at x, you increment x by 1 (x == 2), effectively skipping a character (the character at position 2 is now at position 1
Your if statement is unnecessarily long. In fact, depending on your needs, you could use Character.isDigit or Character.isLetter and Character.isWhiteSpace
String Cleaner = TopField.getText();
Cleaner = Cleaner.toLowerCase();
StringBuilder Combiner = new StringBuilder(Cleaner);
int x =0;
while (x < Combiner.length()) {
char c = Combiner.charAt(x);
if (c >= 'a' && c <= 'z' || c == ' ') {
Combiner.deleteCharAt(x);
} else {
x++;
}
}
From the looks of your code, you appear to wanting to filter a JTextField so it will only allow numeric values. It would be much better to use something like a JSpinner, JFormattedTextField or DocumentFilter and ensure the correctness of the data as it's entered...IMHO
I used a isDigit() function and found the output as incorrect. Look at the code I tested and found problem with the output. Any one explain.
public static void main(String[] args) {
// TODO Auto-generated method stub
String temp="you got 211111 out of 211111?";
StringBuilder cleaner=new StringBuilder(temp);
for(int i=0;i<cleaner.length();i++)
{
char c=cleaner.charAt(i);
if(Character.isDigit(c))
{
cleaner.deleteCharAt(i);
}
}
System.out.println(cleaner);
I am getting output as : you got 111 out of 111?
it is not removing some digits.
Also found that no function called replaceAll() is there in Java.

regular expression for \" in java

I need to write a regular expression for string read from a file
apple,boy,cat,"dog,cat","time\" after\"noon"
I need to split it into
apple
boy
cat
dog,cat
time"after"noon
I tried using
Pattern pattern =
Pattern.compile("[\\\"]");
String items[]=pattern.split(match);
for the second part but I could not get the right answer,can you help me with this?
Since your question is more of a parsing problem than a regex problem, here's another solution that will work:
public class CsvReader {
Reader r;
int row, col;
boolean endOfRow;
public CsvReader(Reader r){
this.r = r instanceof BufferedReader ? r : new BufferedReader(r);
this.row = -1;
this.col = 0;
this.endOfRow = true;
}
/**
* Returns the next string in the input stream, or null when no input is left
* #return
* #throws IOException
*/
public String next() throws IOException {
int i = r.read();
if(i == -1)
return null;
if(this.endOfRow){
this.row++;
this.col = 0;
this.endOfRow = false;
} else {
this.col++;
}
StringBuilder b = new StringBuilder();
outerLoop:
while(true){
char c = (char) i;
if(i == -1)
break;
if(c == ','){
break;
} else if(c == '\n'){
endOfRow = true;
break;
} else if(c == '\\'){
i = r.read();
if(i == -1){
break;
} else {
b.append((char)i);
}
} else if(c == '"'){
while(true){
i = r.read();
if(i == -1){
break outerLoop;
}
c = (char)i;
if(c == '\\'){
i = r.read();
if(i == -1){
break outerLoop;
} else {
b.append((char)i);
}
} else if(c == '"'){
r.mark(2);
i = r.read();
if(i == '"'){
b.append('"');
} else {
r.reset();
break;
}
} else {
b.append(c);
}
}
} else {
b.append(c);
}
i = r.read();
}
return b.toString().trim();
}
public int getColNum(){
return col;
}
public int getRowNum(){
return row;
}
public static void main(String[] args){
try {
String input = "apple,boy,cat,\"dog,cat\",\"time\\\" after\\\"noon\"\nquick\"fix\" hello, \"\"\"who's there?\"";
System.out.println(input);
Reader r = new StringReader(input);
CsvReader csv = new CsvReader(r);
String s;
while((s = csv.next()) != null){
System.out.println("R" + csv.getRowNum() + "C" + csv.getColNum() + ": " + s);
}
} catch(IOException e){
e.printStackTrace();
}
}
}
Running this code, I get the output:
R0C0: apple
R0C1: boy
R0C2: cat
R0C3: dog,cat
R0C4: time" after"noon
R1C0: quickfix hello
R1C1: "who's there?
This should fit your needs pretty well.
A few disclaimers, though:
It won't catch errors in the syntax of the CSV format, such as an unescaped quotation mark in the middle of a value.
It won't perform any character conversion (such as converting "\n" to a newline character). Backslashes simply cause the following character to be treated literally, including other backslashes. (That should be easy enough to alter if you need additional functionality)
Some csv files escape quotes by doubling them rather than using a backslash, this code now looks for both.
Edit: Looked up the csv format, discovered there's no real standard, but updated my code to catch quotes escaped by doubling rather than backslashes.
Edit 2: Fixed. Should work as advertised now. Also modified it to test the tracking of row and column numbers.
First thing: String.split() uses the regex to find the separators, not the substrings.
Edit: I'm not sure if this can be done with String.split(). I think the only way you could deal with the quotes while only matching the comma would be by readahead and lookbehind, and that's going to break in quite a lot of cases.
Edit2: I'm pretty sure it can be done with a regular expression. And I'm sure this one case could be solved with string.split() -- but a general solution wouldn't be simple.
Basically, you're looking for anything that isn't a comma as input [^,], you can handle quotes as a separate character. I've gotten most of the way there myself. I'm getting this as output:
apple
boy
cat
dog
cat
time\" after\"noon
But I'm not sure why it has so many blank lines.
My complete code is:
String input = "apple,boy,cat,\"dog,cat\",\"time\\\" after\\\"noon\"";
Pattern pattern =
Pattern.compile("(\\s|[^,\"\\\\]|(\\\\.)||(\".*\"))*");
Matcher m = pattern.matcher(input);
while(m.find()){
System.out.println(m.group());
}
But yeah, I'll echo the guy above and say that if there's no requirement to use a regular expression, then it's probably simpler to do it manually.
But then I guess I'm almost there. It's spitting out ... oh hey, I see what's going on here. I think I can fix that.
But I'm going to echo the guy above and say that if there's no requirement to use a regular expression, it's probably better to do it one character at a time and implement the logic manually. If your regex isn't picture-perfect, then it could cause all kinds of unpredictable weirdness down the line.
I am not really sure about this but you could have a go at Pattern.compile("[\\\\"]");
\ is an escape character and to detect a \ in the expression, \\\\ could be used.
A similar thing worked for me in another context and I hope it solves your problem too.

Is there a faster method then StringBuilder for a max 9-10 step string concatenation?

I have this code to concate some array elements:
StringBuilder sb = new StringBuilder();
private RatedMessage joinMessage(int step, boolean isresult) {
sb.delete(0, sb.length());
RatedMessage rm;
for (int i = 0; i <= step; i++) {
if (mStack[i] == null)
continue;
rm = mStack[i].getCurrentMsg();// msg is built upfront, this just returns, it's a getter method call
if (rm == null || rm.msg.length() == 0)
continue;
if (sb.length() != 0) {
sb.append(", ");
}
sb.append(rm.msg);
}
rm.msg=sb.toString();
return rm;
}
Important the array holds max 10 items, so it's not quite much.
My trace output tells me this method is called 18864 times, 16% of the runtime was spent in this method. Can I optimize more?
First of all I won't reuse StringBuilder and always create new instance. That will be certainly faster, because it would allow GC to use young generation heap area.
Another little trick that allows to eliminate at least one if statement is to rewrite your code like this:
String separator = "";
for (int i = 0; i <= step; i++) {
...
sb.append(separator);
sb.append(rm.msg);
separator = ", ";
}
some ideas:
1) Do you initialize the StringBuilder with the estimated max capacity? This can save the time spent in the inner array re-allocation & copying.
2) Maybe you can append a trailing comma in the loop, and avoid the condition for string length inside the loop. Instead, add a single condition at the end of the method, and remove the trailing comma if needed.
You can make the following change (showing only the differences):
String separator = "";
for (int i = 0; i <= step; i++) {
// ...
sb.append(separator).append(rm.msg);
separator = ", ";
}
It gets rid if an extra if 9 times at the cost of adding an empty string once. You should measure if it helps at all with the data you are using before you decide to keep this change :-)
If your function is supposed to concatenate array elements, why are you passing in all these crazy values and unused parameters?
private string joinMessage( string[] myArray)
{
StringBuilder sbr = new StringBuilder();
for(int i = 0; i < myArray.Length; i++)
{
if(!string.IsNullOrEmpty(myArray[i])
{
sbr.Append(myArray[i]);
sbr.Append(",")
}
}
return sbr.ToString();
}
Take a step through each element in the stack first, taking a count of the sum of all the string lengths.
Then you can use
sb.ensureCapacity(totalEndLength);
String builder works like an array list, so you might be rebuilding that array with most of your appends.
A bit of a mini-optimization... take the test-for-comma outside of the loop.
private RatedMessage joinMessage(int step, boolean isresult) {
sb.delete(0, sb.length());
for (int i = 0; i <= step; i++) {
if (mStack[i] == null)
continue;
rm = mStack[i].getCurrentMsg();
if (rm == null || rm.msg.length() == 0)
continue;
sb.append(rm.msg).append(", ");
}
if (sb.length() > 2) {
sb.delete(sb.length() - 2, 2);
}
return sb.toString();
}
Other suggestions would be:
Make sure that when the StringBuilder is constructed you set its initial length to a decent value
I'm not sure of the context of the rest of the code, but maybe you can pre-ensure that mStack[i] will not be null, and that mStack[i].getCurrentMessage() is not null or empty - this will allow you to take more if statements outside of the loop.
If your mStack is a Collection instead of an array, you can just do mStack.toString(), which will print a readable string of the array. That might be easier than writing your own.
16% runtime in this method including or excluding called methods? The getCurrentMsg() call might be a hidden problem, if it creates lots of objects.
Besides that, I suggest to take all the needed Strings out of your stack and afterwards call
StringUtils.join(myStrings, ", ")
using the Apache commons library. Try relying on tested code for such low level things instead of optimizing it yourself every other day. In the end that will give you better optimization results because you will be able to concentrate on the big picture (i.e. the overall design of your software).
Have a separate copy of the mStack array with the string representation, by default initialized with empty String, so your loop would be:
String [] mStackCopy = new String[]{"","","","","","","","","","",};
// or mstackCopy = new String[mStack.length];
// for( int i = 0 ; i < mStackCopy.lenght ; i++ ) { mStack[i] = "" }
Also, create the StringBuilder with enough capacity:
StringBuilder sb = new StringBuilder( 10000 );// 10k chars or whatever makes sense.
So, when you need to create the message you would simply:
for (int i = 0; i <= step; i++) {
sb.append( mStackCopy[i] );
}
And empty parts won't cause a problem because they are blank already:
You may even hard code it:
sb.append( mStackCopy[0]);
sb.append( mStackCopy[1]);
sb.append( mStackCopy[2]);
sb.append( mStackCopy[3]);
sb.append( mStackCopy[4]);
sb.append( mStackCopy[5]);
sb.append( mStackCopy[6]);
sb.append( mStackCopy[7]);
sb.append( mStackCopy[8]);
sb.append( mStackCopy[9]);
But this would cause more pain than relief in the future, guaranteed.
When you add something to your mStack:
MStack item = new MStack();
item.setCurrentMessage("Some message");
....
Just make a copy of the message and append the ", " already.
addToMStack(int position, MStackItem item ) {
mStack[position] = item;
mStackCopy[position] = item.getCurrentMessage() + ", ";
}
And depending on the occurrence of nulls ( if its low ) you can catch them
addToMStack(int position, MStackItem item ) {
if( item == null ) { return; }
mStack[position] = item;
try {
mStackCopy[position] = item.getCurrentMessage() + ", ";
} catch( NullPointerException npe ){}
}
Which is horrendous
Or validate it:
addToMStack(int position, MStackItem item ) {
if( item == null ) { return; }
mStack[position] = item;
mStackCopy[position] = item.getCurrentMessage() + ", ";
}
I'm pretty sure your method is doing something else that you don't show us. Probably the reason is there.
Also, 16% is not that bad, if 100% is 1sec.
Sometimes there's just nothing else to optimize. I think this is one of such cases. You can try to shave off an instruction or two maybe, but you won't get it much faster in principle.
I think the only thing left to optimize is to consider why you are calling it 18864 times and whether some of those calls can be avoided altogether. Perhaps some are not needed, or perhaps you can cache the result in some cases.
Use StringBuilder + StringUtils from Apache Commons Lang. Looping through a String with a separator and chomping is what StringUtils is all about!
private RatedMessage joinMessage(int step, boolean isresult) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i <= step; i++) {
WhateverTypeIsFromMStackVariable stackVariable = mStack[i];
String message = getMessage(stackVariable);
if(StringUtils.isNotEmpty(message)) {
builder.append(message).append(", ");
}
}
RatedMessage rm = new RatedMessage();
rm.msg = StringUtils.chomp(builder.toString(), ", ");
return rm;
}
private static String getMessage(WhateverTypeIsFromMStackVariable stackVariable) {
if(stackVariable != null) {
RatedMessage message = stackVariable.getCurrentMsg();
if(message != null) {
return message.msg;
}
}
return null;
}
Apache Commons Lang is here: http://commons.apache.org/lang/

Categories