Java reading csv and understanding types - java

I need to read from a csv file. The file has some different types like int, float, String, char. How can I know what the type is?
I did write some code for it but my problem is with floating point numbers. In my computer java say that "7.9" is not a floating point number, but "7,9" is.
But on some computers "7.9" is a float. How can I solve this?
public static void Read(String filename) throws FileNotFoundException{
File file = new File(filename);
Scanner scanner1 = new Scanner(file);
String line ;
Scanner scanner;
int a;
float f;
String temp ;
while(scanner1.hasNextLine()){
line = scanner1.nextLine();
scanner = new Scanner(line);
scanner.useDelimiter(",|\\n");
while (scanner.hasNext()){
if (scanner.hasNextInt()){
a = scanner.nextInt();
System.err.printf("Int :%d",a);
}
else if(scanner.hasNextFloat()){
f = scanner.nextFloat();
System.err.printf("flt :%f",f);
}
else {
temp = scanner.next();
if(temp.length() == 1)
System.err.printf("char:%s",temp);
else
System.err.printf("string:%s",temp);
}
}
System.err.printf("\n");
scanner.close();
}
}

The more I read this more I realize I was wrong.
If your CSV data is like
1,2,3,4
Then it could be (1,2 and 3,4) eg (1.2, 3.4) or it could be the integers 1 through 4
If its properly quoted
"1,2","3,4"
Then your parser wont work because its not using quotes as the delimiters.
So its hard to say what is causeing your issue with out seeing the data.
You could add handeling of the quotes in your scanner but there are more cases inolved if your vlaues contain quotes themselves
Ideally use a proper CSV parse like http://opencsv.sourceforge.net/
Otherwise you need to walk through your data nad make sure your parse is covering all the cases you have today, and might have tomorrow.
A hack work around would be to modify your strings using replaceAll(".",","); but there are many pitfulls when doing that again, your scanner may confuse the elements as new entries in your CSV.
Specifically to change from representing decimals from 1,2 to 1.2 you can modify the Local for the number types you want with
scanner1.useLocale(Locale.US);
From what I can tell there is no way to have more than one locale for the scanner. One approach is to use two scanners, with two different Locales at the same time to parse the float differently.

You can change the scanner's locale using #useLocale(java.util.Locale)
Set the locale to one which uses . as the decimal point. I.e)
scanner.useDelimiter(",|\\n");
scanner.useLocale( Locale.US ); // Use '.' as decimal point

Related

Why do I get wrong mathematical results when using scanner class and delimiters for getting a double in Java?

I am writing a program where I have to get a user input, saved as a double. The user must be able to put it using both ',' and '.' as a delimiter - however they want. I tried using useDelimiter which works only partially - it does indeed accept both values (e.g 4.5 and 4,5) but when I later use the entered value in a mathematical equation, I get wrong results - it seems to round the user input down to the closest integer and as an effect no matter whether I enter, 4 or 4.5 or 4,5 or 4.8 etc., I get the same result, which is actually only true to 4.
Does anyone happen to know why it doesn't work?
double protectiveResistor=0; //must be a double, required by my teacher
double voltage= 5;
System.out.println("Please provide the resistance.");
Scanner sc= new Scanner(System.in);
sc.useDelimiter("(\\p{javaWhitespace}|\\.|,)");
try
{
protectiveResistor=sc.nextDouble();
}
catch(InputMismatchException exception)
{
System.out.println("Wrong input!");
System.exit(1);
}
if (protectiveResistor<0){
System.err.println("Wrong input!");
System.exit(1);
}
double current = (double)voltage/protectiveResistor;
double power = (double)current*current*protectiveResistor;
Thank you!
The useDelimiter method is for telling the Scanner what character will separate the numbers from each other. It's not for specifying what character will be the decimal point. So with your code, if the user enters either 4.5 or 4,5, the Scanner will see that as two separate inputs, 4 and 5.
Unfortunately, the Scanner doesn't have the facility to let you specify two different characters as decimal separators. The only thing you can really do is scan the two numbers separately, then join them together into a decimal number afterwards. You will want to scan them as String values, so that you don't lose any zeroes after the decimal point.
What useDelimiter() does is split the input on the specified delimiter.
As an example, if you have the input of 4,5, the following code will print "4".
Scanner sc= new Scanner(System.in);
sc.useDelimiter(",");
System.out.println(sc.next())
If you also want to print the second part, after the ',', you need to add another line to get the next value, which would in this example print
"4
5":
Scanner sc= new Scanner(System.in);
sc.useDelimiter(",");
System.out.println(sc.next())
System.out.println(sc.next())
In your code you can do it like this:
Scanner sc= new Scanner(System.in);
sc.useDelimiter("(\\p{javaWhitespace}|\\.|,)");
try
{
String firstPart = "0";
String secondPart = "0";
if (sc.hasNext()) {
firstPart = sc.next();
}
if (sc.hasNext()) {
secondPart = sc.next();
}
protectiveResistor = Double.parseDouble(firstPart + "." + secondPart)
}
// Rest of your code here
What this code does is split the input on whitespace, '.' and ','. For a floating point value you expect one part before the decimal point and one after it. Therefore, you expect the scanner to have split the input in two parts. These two parts are assigned to two variables, firstPart and secondPart. In the last step, the two parts are brought together with the '.' as decimal point, as expected by Java and parsed back into a variable of type Double.

InputStreamReader, Buffered Reader, Java issue with reading standard input

I have a standard input that contains lines of text. Each line contains 2 numbers that are separated by a comma. I need to separate the two numbers so that I can use them in another function. I don't know what would be a good way to read each line, separate the numbers and then use them to call function until there are no more lines to be read. I read the documentation regarding InputStreamReader and BufferedReader, however, since I'm relatively new to java they didn't make much sense.
public static void main(String[] args) throws IOException {
InputStreamReader reader = new InputStreamReader(System.in);
BufferedReader in = new BufferedReader(reader);
try {
double num1 = Double.parseDouble(in.readLine());
double num2 = Double.parseDouble(in.readLine());
Main.function(num1,num2);
}
When you call in.readLine() then you get a string, probably something like "42.1,100.2". The next step would be splitting the string and after that you can convert the split string(s) to numbers.
String line = in.readLine(); // read one line
String[] parts = line.split(","); // split the line around the comma(s)
double num1 = Double.parseDouble(parts[0]); // convert the first part to double
double num2 = Double.parseDouble(parts[1]); // convert the second part to double
Main.function(num1, num2);
Note that this only reads from one line in the file (many lines -> looping) and that this only works correctly when the input is well formatted. You probably want to lookup the trim() method on String.
Double is not recognize the commas instead you will have to take the input string and replace all commas with empty strings. e.g. you have this input
String input = "123,321.3" ;
input = input.replaceAll("," , "");
in result you will have this
input -> "123321.3"
Then you can parse the string to double.
Hope it will help.
Regards , Erik.

Scanner.nextDouble(): reading double with "."

I'm have a little problem with the Java class Scanner:
I need to read a file (.dat) that contains Double values, but it seems like the method Scanner.nextDouble only recognize number written like this: 1234,5678 , with a "," but not with a ".". I wanted to know if there was a way to change that, because the file is generated by another software, so I can't make it change the "," for a ".".
Thanks
Robin
It seems like your default Locale uses a comma-based decimal separator for double values. Try using
scanner.useLocale(Locale.ENGLISH);
Replace , with .
Example:
Scanner sc = new Scanner(new File("myNumbers"));
while (sc.hasNext()) {
String s = sc.next();
Double d = (Double)s.replace(",",".");
}

How do I change the delimiter from a text file?

Let's say I got a textfile.txt that I want to read from. This is the text in the file:
23:years:old
15:years:young
Using the useDelimiter method, how can I tell my program that : and newlines are delimiters? Putting the text in one line and using useDelimter(":"); works. The problem is when I got several lines of text.
Scanner input = new Scanner(new File("textfile.txt));
input.useDelimiter(:);
while(data.hasNextLine()) {
int age = input.nextInt();
String something = input.next();
String somethingelse = input.next();
}
Using this code I will get an inputMisMatch error.
Try
scanner.useDelimiter("[:]+");
The complete code is
Scanner scanner = new Scanner(new File("C:/temp/text.txt"));
scanner.useDelimiter("[:]+");
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
The output is
23
years
old
15
years
young
Use this code
Scanner input;
String tokenizer[];
try {
input = new Scanner(new File("D:\\textfile.txt"));
input.useDelimiter("\\n");
while(input.hasNextLine()) {
tokenizer = input.next().split(":");
System.out.println(tokenizer[0]+" |"+tokenizer[1]+" | "+tokenizer[2]);
}
}catch(Exception e){}
It will give you output like
23 |years | old
15 |years | young
You have two ways to do this:
Concatenate the string to make it one line.
delimit "newline" first, then delimit ":" each return string token.
If all you want is to get everything split up all at once then I guess you can use
useDelimiter(":\\n")
That should split on both : and newspace but it is not the most efficient way of processing data, especially if each line of text is set out in the same format and represents a complete entry. If that is the case then my suggestion would be to only split on a new line to begin with, like this;
s.useDelimiter("\\n");
while(s.hasNext()){
String[] result = s.next.split(":");
//do whatever you need to with the data and store it somewhere
}
This will allow you to process the data line by line and will also split it at the required places. However if you do plan on going through line by line I recommend you look at BufferedReader as it has a readLine() function that makes things a lot easier.
As long as all the lines have all three fields you can just use input.useDelimiter(":\n");
you probably wants to create a delimiter pattern which includes both ':' and newline
I didn't test it, but [\s|:]+ is a regular expression that matches one or more whitespace characters, and also ':'.
Try put:
input.useDelimiter("[\\s|:]+");

How do I convert a String to Double in Java using a specific locale?

I want to convert some numbers which I got as strings into Doubles, but these numbers are not in US standard locale, but in a different one. How can I do that?
Try java.text.NumberFormat. From the Javadocs:
To format a number for a different Locale, specify it in the call to getInstance.
NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
You can also use a NumberFormat to parse numbers:
myNumber = nf.parse(myString);
parse() returns a Number; so to get a double, you must call myNumber.doubleValue():
double myNumber = nf.parse(myString).doubleValue();
Note that parse() will never return null, so this cannot cause a NullPointerException. Instead, parse throws a checked ParseException if it fails.
Edit: I originally said that there was another way to convert to double: cast the result to Double and use unboxing. I thought that since a general-purpose instance of NumberFormat was being used (per the Javadocs for getInstance), it would always return a Double. But DJClayworth points out that the Javadocs for parse(String, ParsePosition) (which is called by parse(String)) say that a Long is returned if possible. Therefore, casting the result to Double is unsafe and should not be tried!
Thanks, DJClayworth!
NumberFormat is the way to go, but you should be aware of its peculiarities which crop up when your data is less than 100% correct.
I found the following usefull:
http://www.ibm.com/developerworks/java/library/j-numberformat/index.html
If your input can be trusted then you don't have to worry about it.
Just learning java and programming. Had similar question. Found something like this in my textbook:
Scanner sc = new Scanner(string);
double number = sc.nextDouble();
The book says that a scanner automatically decodes what's in a String variabel and that the Scanner class automatically adapts to the language of the set Locale, system Locale being the default, but that's easy to set to something else.
I solved my problem this way. Maybe this could work for the above issue instead of parsing?
Addition: The reason I liked this method was the fact that when using swing dialouge boxes for input and then trying to convert the string to double with parse I got a NumberFormatException. It turned out that parse exclusively uses US-number formatting while Scanner can handle all formats. Scanner made the input work flawlessly even with the comma (,) decimal separator. Since the most voted up answer uses parse I really don't see how it would solve this particular problem. You would have to input your numbers in US format and then convert them to your locale format. That's rather inconvenient when ones numeric keybord is fitted with a comma.
Now you're all free to shred me to pieces ;)
You use a NumberFormat. Here is one example, which I think looks correct.
Use NumberFormat.getNumberInstance(Locale)
This should be no problem using java.text.DecimalFormat.
Do you know which locale it is? Then you can use
DecimalFormat format = DecimalFormat.getInstance(theLocale);
format.parse(yourString);
this will even work for scientific notations, strings with percentage signs or strings with currency symbols.
Here is how you use parseDouble to convert a String to a Double:
doubleExample.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class doubleExample {
public static void main(String[] args) {
Double myDouble = new Double("0");
System.out.println("Please enter a number:");
try
{
//get the number from console
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
myDouble = Double.parseDouble(br.readLine());
}
//if invalid value was entered
catch(NumberFormatException ne)
{
System.out.println("Invalid value" + ne);
System.exit(0);
}
catch(IOException ioe)
{
System.out.println("IO Error :" + ioe);
System.exit(0);
}
System.out.println("Double value is " + myDouble);
}
}

Categories