Streamtokenizer to read very large numbers? - java

I have to take an input containing large numbers of order 10^9 in Java. How do I handle Inputs fast? Also since streamtokenizer.nval gives a double, how can I read larger values??

Before parsing, reset the tokenizer syntax table and initialize it to recognize numbers as words:
StreamTokenizer tokenizer = new StreamTokenizer(r);
tokenizer.resetSyntax();
tokenizer.whitespaceChars(0, 32);
tokenizer.wordChars('0', '9');
tokenizer.wordChars('-', '.');
tokenizer.wordChars('+', '+');
tokenizer.wordChars('a', 'z');
tokenizer.wordChars('A', 'Z');
tokenizer.wordChars(0xa0, 0xff); // not really needed here. */
tokenizer.slashSlashComments(true);
tokenizer.slashStarComments(true);
tokenizer.quoteChar('"');
tokenizer.quoteChar('\'');
Then, when encountering a word, you check whether it is parseable as a number (a bit crude here, but it shows the general idea):
...
case StreamTokenizer.TT_WORD:
if ("true".equals(tokenizer.sval)) {
result = Boolean.TRUE;
} else if ("false".equals(tokenizer.sval)) {
result = Boolean.FALSE;
} else if ("null".equals(tokenizer.sval)) {
result = null;
} else {
try {
result = Long.parseLong(tokenizer.sval);
} catch(NumberFormatException e) {
try {
result = Double.parseDouble(tokenizer.sval);
} catch (NumberFormatException e2) {
throw new IllegalStateException(
"Unexpected token: " + tokenizer.toString());
}
}
}
tokenizer.nextToken();
break;
Whether this works depends on the use case: If you want to parse expressions (and not just JSON as in my case), you probably don't want to set + or - as word characters, but the general idea should still work by treating them as unary operators and detecting constants at a later stage.

Related

How to detect if the user inputs a fraction

I want to only accept fractions.
Here's what I've done so far:
if (nm == 2) {
System.out.print("First Fraction: ");
aa = sc.nextLine();
System.out.print("Second Fraction: ");
bb = sc.nextLine();
if (aa.startsWith("[0-9].*") && aa.contains("/") && aa.endsWith("[0-9].*") && bb.startsWith("[0-9].*") && bb.contains("/") && bb.endsWith("[0-9].*")) {
ar = new Arithmetic_Operations(aa, bb);
} else {
System.out.println("Please Input Fraction");
System.out.println();
break;
}
}
Arithmetic_Operations.Add();
How do I detect that the String starts and ends with a number?
Also, I have no idea what I was doing with the .start and .end codes.
The question can be expressed more generally as "how to write a parser". Generally speaking, regex is not the most straightforward way to tackle it. See here for a more thorough explanation, which can be summarized in your case as follows:
Write a method to check that the input has exactly:
a numerator
a denominator
a division sign between them
This is a pretty simple case, so it'd be overkill to write something really complicated for it but one approach without using regex and with three separate simple "functions" (steps) would be the following:
boolean isFraction(String text) {
String[] numeratorAndDenominator = text.split("/");
// check for the division sign
if (numeratorAndDenominator.length != 2) {
return false;
}
// check that the numerator is an integer
try {
Integer.parseInt(numeratorAndDenominator[0].trim());
} catch (NumberFormatException e) {
return false;
}
// check that the denominator is also an integer
try {
Integer.parseInt(numeratorAndDenominator[1].trim());
} catch (NumberFormatException e) {
return false;
}
return true;
}
For more complicated stuff it would probably be more worth your time to look at existing parsing libraries for mathematical expressions. One possibility might be mathparser.
If you want to detect simple fractions, you can use below method.
public static boolean isFraction(String text){
return (text.matches("[0-9]+[/][0-9]+"));
}
If you want a more complex solution, you need to also check,
+, - signs
Parentheses
More than one /
Fractions
If you are implementing these via regex, below link will help you.
Java regex

How to validate phone number

I am trying to validate phone numbers in java. In my country, phone numbers either begin with 9 or 8 and only have 8 numbers. I have done
try {
Integer.parseInt(phoneNo);
}
catch (NumberFormatException e) {
msg += "Plese enter amount in Integers.\n";
}
if (phoneNo.length() == 0)
msg += "Please Enter Phone Number.\n";
if (phoneNo.length() != 8)
msg += "Invalid Phone Number.\n";
However I need to validate when the first digit of the number isn't 9 or 8. I am not entirely sure of how I am supposed to do that. Please explain how your code works as I am a student and I am trying to learn.
Just in case you are looking for a regular expression solution.
You can do use the following pattern ^(?=(?:[8-9]){1})(?=[0-9]{8}).* to perform the check.
Essentially what it does is;
From first character position ^
Look ahead and see if the first character is a 8 or 9 (?=(?:[8-9]){1})
Then see if there are a total of 8 digits (?=[0-9]{8})
If the above conditions is a match then mark this as matched .*
public static void main(String[] args) {
String telephoneNr = "88765432";
if (telephoneNr.matches("^(?=(?:[8-9]){1})(?=[0-9]{8}).*")) {
System.out.println("Valid phone number!");
}
else {
System.out.println("Invalid!");
}
}
Output:
Valid phone number!
The methods that you need to put this together are readily available on the String and Character classes.
Here is an example program that does what you are looking for:
public class Foo {
public static void main(String[] args) {
// First try null and the empty string
System.out.println(isValidPhoneNumber(null));
System.out.println(isValidPhoneNumber(""));
// Now try an otherwise valid string that doesn't have the right first character
System.out.println(isValidPhoneNumber("01234567"));
// Now try an invalid string
System.out.println(isValidPhoneNumber("9a934581"));
// Finally a valid number
System.out.println(isValidPhoneNumber("94934581"));
}
static boolean isValidPhoneNumber(String phoneNo) {
// First validate that the phone number is not null and has a length of 8
if (null == phoneNo || phoneNo.length() != 8) {
return false;
}
// Next check the first character of the string to make sure it's an 8 or 9
if (phoneNo.charAt(0) != '8' && phoneNo.charAt(0) != '9') {
return false;
}
// Now verify that each character of the string is a digit
for (char c : phoneNo.toCharArray()) {
if (!Character.isDigit(c)) {
// One of the characters is not a digit (e.g. 0-9)
return false;
}
}
// At this point you know it is valid
return true;
}
}
The output it produces is:
false
false
false
false
true
The final for-each loop could avoid re-checking the first character by using a for loop with an explicit counter, but the performance gain of not checking a single int doesn't outweigh the cleaner code and better readability of the for each construct.
Edit: also please note that I removed the validation error messages from the original question for better readability as the OP asked to explain what the code was doing.
Instead of taking the phone number in a Integer variable take it in a String variable.
Then check whether the 1st number is 9, 8 or not by using stringVariable.charAt(0)
and for length of the phone number use int len=stringVariable.length();
You can check the first character of the phoneNo:
if (phoneNo.charAt(0) != '9' && phoneNo.charAt(0) != '8') {
// the first character is not a 9 or an 8
}
Documentation for charAt from Oracle.

function to identify whether the value can be converted to int, or double, or anything else?

If there is a string variable containing a number string , is there any function to identify whether the value can be converted to int, or double, or anything else?? i need the function name in java
String sent3 = "123";
System.out.println(sent3.matches("[0-9]+"));
System.out.println(sent3.matches("[0-9]+\\.[0-9]+"));// for double
output :- true
If the output is true then it can be converted into int.
Follow this link for more regex
My solution involves trying to parse the string into the various types, and then looking for exceptions that Java might throw. This is probably an inefficient solution, but the code is relatively short.
public static Object convert(String tmp)
{
Object i;
try {
i = Integer.parseInt(tmp);
} catch (Exception e) {
try {
i = Double.parseDouble(tmp);
} catch (Exception p) {
return tmp; // a number format exception was thrown when trying to parse as an integer and as a double, so it can only be a string
}
return i; // a number format exception was thrown when trying to parse an integer, but none was thrown when trying to parse as a double, so it is a double
}
return i; // no numberformatexception was thrown so it is an integer
}
You can then use this function with the following lines of code:
String tmp = "3"; // or "India" or "3.14"
Object tmp2 = convert(tmp);
System.out.println(tmp2.getClass().getName());
You can convert the function into inline code to test if it is an integer, for example:
String tmp = "3";
Object i = tmp;
try {
i = Integer.parseInt(tmp);
} catch (Exception e) {
// do nothing
}
I was a little sloppy and tried to catch normal Exceptions, which is rather generic - I suggest you use "NumberFormatException" instead.
String test = "1234";
System.out.println(test.matches("-?\\d+"));
test = "-0.98";
System.out.println(test.matches("-?\\d+\\.\\d+"));
The first one matches (ie prints true) any integer (not int, integer) with an optional - sign in front. The second one matches any double value with an optional - sign, at least one digit before a required decimal point, and at least on digit following the decimal point.
Also, the function name is String.matches and it uses regular expressions.

Equivalent of 'where' fortran keyword in Java?

I'm writing a Java program in which I'm checking a list against a string, and then doing stuff to that. In fortran I'd write something along the lines of
where(list(:)==stringToCheck){
...
statements
...
}
Instead I have a headache of a block of for-loops, if staments and breaks all over the place. No perhaps I could neaten the code a little but it still feels far more inefficient than fortran.
Edit, this is the code I've resorted to:
for(int idx=0;idx<player.get_charactersOwned().size();idx++)
{
if(player.get_charactersOwned().get(idx).get_characterName().equals(charName))
{
/* Add character to the game
* Add game to the character*/
System.out.println("Character "+charName+" Found ");
gameToMake.addCharacters(player.get_charactersOwned().get(idx));
player.get_charactersOwned().get(idx).addGame(gameToMake);
break;
}else
{
System.err.println("Character "+ charName +" not found");
System.out.println("Shall I add that Character? y/n ");
choice = scanner.nextLine();
if(choice.equalsIgnoreCase("y"))
{
charName = scanner.nextLine();
Character character = new Character(charName);
characterTempList.add(character);
player.addCharacter(characterTempList);
gameToMake.addCharacters(player.get_charactersOwned().get(idx));
player.get_charactersOwned().get(idx).addGame(gameToMake);
break;
}else{break;}
}
}
As tempting as it is to fix this code, I'd much rather use a work around.
Is there a Java equivilant of this without the use of external libraries?
No, there isn't an equivalent in Java. Instead if you need to check if a list of characters (each with a name) contains a character name then simply do this:
// search the name
boolean found = false;
for (Character c : player.get_charactersOwned()) {
if (c.get_characterName().equals(charName)) {
found = true;
break;
}
}
// perform the check
if (found) {
// do something
} else {
// do something else
}
And by the way, Character is a bad name for your class, it clashes with Java's own Character class. Rename it if possible, to avoid confusion. Alternatively, the loop could have been written like this:
boolean found = false;
for (int i = 0, n = player.get_charactersOwned().size(); i < n && !found; i++) {
Character c = player.get_charactersOwned().get(i);
if (c.get_characterName().equals(charName)) {
found = true;
}
}

How to parse a currency Amount (US or EU) to float value in Java

In Europe decimals are separated with ',' and we use optional '.' to separate thousands. I allow currency values with:
US-style 123,456.78 notation
European-style 123.456,78 notation
I use the next regular expression (from RegexBuddy library) to validate the input. I allow optional two-digits fractions and optional thousands separators.
^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{0,2})?|(?:,[0-9]{3})*(?:\.[0-9]{0,2})?|(?:\.[0-9]{3})*(?:,[0-9]{0,2})?)$
I would like to parse a currency string to a float. For example
123,456.78 should be stored as 123456.78
123.456,78 should be stored as 123456.78
123.45 should be stored as 123.45
1.234 should be stored as 1234
12.34 should be stored as 12.34
and so on...
Is there an easy way to do this in Java?
public float currencyToFloat(String currency) {
// transform and return as float
}
Use BigDecimal instead of Float
Thanks to everyone for the great answers. I have changed my code to use BigDecimal instead of float. I will keep previous part of this question with float to prevent people from doing the same mistakes I was gonna do.
Solution
The next code shows a function which transforms from US and EU currency to a string accepted by BigDecimal(String) constructor. That it is to say a string with no thousand separator and a point for fractions.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TestUSAndEUCurrency {
public static void main(String[] args) throws Exception {
test("123,456.78","123456.78");
test("123.456,78","123456.78");
test("123.45","123.45");
test("1.234","1234");
test("12","12");
test("12.1","12.1");
test("1.13","1.13");
test("1.1","1.1");
test("1,2","1.2");
test("1","1");
}
public static void test(String value, String expected_output) throws Exception {
String output = currencyToBigDecimalFormat(value);
if(!output.equals(expected_output)) {
System.out.println("ERROR expected: " + expected_output + " output " + output);
}
}
public static String currencyToBigDecimalFormat(String currency) throws Exception {
if(!doesMatch(currency,"^[+-]?[0-9]{1,3}(?:[0-9]*(?:[.,][0-9]{0,2})?|(?:,[0-9]{3})*(?:\\.[0-9]{0,2})?|(?:\\.[0-9]{3})*(?:,[0-9]{0,2})?)$"))
throw new Exception("Currency in wrong format " + currency);
// Replace all dots with commas
currency = currency.replaceAll("\\.", ",");
// If fractions exist, the separator must be a .
if(currency.length()>=3) {
char[] chars = currency.toCharArray();
if(chars[chars.length-2] == ',') {
chars[chars.length-2] = '.';
} else if(chars[chars.length-3] == ',') {
chars[chars.length-3] = '.';
}
currency = new String(chars);
}
// Remove all commas
return currency.replaceAll(",", "");
}
public static boolean doesMatch(String s, String pattern) {
try {
Pattern patt = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
Matcher matcher = patt.matcher(s);
return matcher.matches();
} catch (RuntimeException e) {
return false;
}
}
}
To answer a slightly different question: don't use the float type to represent currency values. It will bite you. Use a base-10 type instead, like BigDecimal, or an integer type like int or long (representing the quantum of your value - penny, for example, in US currency).
You will not be able to store an exact value - 123.45, say, as a float, and mathematical operations on that value (such as multiplication by a tax percentage) will produce rounding errors.
Example from that page:
float a = 8250325.12f;
float b = 4321456.31f;
float c = a + b;
System.out.println(NumberFormat.getCurrencyInstance().format(c));
// prints $12,571,782.00 (wrong)
BigDecimal a1 = new BigDecimal("8250325.12");
BigDecimal b1 = new BigDecimal("4321456.31");
BigDecimal c1 = a1.add(b1);
System.out.println(NumberFormat.getCurrencyInstance().format(c1));
// prints $12,571,781.43 (right)
You don't want to muck with errors when it comes to money.
With respect to the original question, I haven't touched Java in a little while, but I know that I'd like to stay away from regex to do this kind of work. I see this recommended; it may help you. Not tested; caveat developer.
try {
String string = NumberFormat.getCurrencyInstance(Locale.GERMANY)
.format(123.45);
Number number = NumberFormat.getCurrencyInstance(locale)
.parse("$123.45");
// 123.45
if (number instanceof Long) {
// Long value
} else {
// too large for long - may want to handle as error
}
} catch (ParseException e) {
// handle
}
Look for a locale with rules that match what you expect to see. If you can't find one, use multiple sequentially, or create your own custom NumberFormat.
I'd also consider forcing users to enter values in a single, canonical format. 123.45 and 123.456 look way too similar for my tastes, and by your rules would result in values that differ by a factor of 1000. This is how millions are lost.
As a generalized solution you can try
char[] chars = currency.toCharArray();
chars[currency.lastIndexOf(',')] = '.';
currency = new String(chars);
instead of
if(currency.length()>=3) {
char[] chars = currency.toCharArray();
if(chars[chars.length-2] == ',') {
chars[chars.length-2] = '.';
} else if(chars[chars.length-3] == ',') {
chars[chars.length-3] = '.';
}
currency = new String(chars);
}
so that fractional part can be of any length.
Try this.............
Locale slLocale = new Locale("de","DE");
NumberFormat nf5 = NumberFormat.getInstance(slLocale);
if(nf5 instanceof DecimalFormat) {
DecimalFormat df5 = (DecimalFormat)nf5;
try {
DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance(slLocale);
decimalFormatSymbols.setGroupingSeparator('.');
decimalFormatSymbols.setDecimalSeparator(',');
df5.setDecimalFormatSymbols(decimalFormatSymbols);
df5.setParseBigDecimal(true);
ParsePosition pPosition = new ParsePosition(0);
BigDecimal n = (BigDecimal)df5.parseObject("3.321.234,56", pPosition);
System.out.println(n);
}catch(Exception exp) {
exp.printStackTrace();
}
}
A quick a dirty hack could be:
String input = input.replaceAll("\.,",""); // remove *any* , or .
long amount = Long.parseLong(input);
BigDecimal bd = BigDecimal.valueOf(amount).movePointLeft(2);
//then you could use:
bd.floatValue();
//but I would seriously recommended that you don't use floats for monetary amounts.
Note this will only work if the input is in the form ###.00, ie with exactly 2 decimal places. For example input == "10,022" will break this rather naive code.
Alternative is to use the BigDecimal(String) constructor, but you'll need to convert those euro style numbers to use '.' as the decimal separator, in addition to removing the thousand separators for both.

Categories

Resources