DecimalFormat - can it handle phone numbers, SSNs, etc.? - java

I've found the following with unexpected results:
format number result expected
"000-00-0000" 123456789L "123456789--" "123-45-6789"
"(###)###-####" 1234567890L "(1234567890)-" "(123)456-7890"
"_($* "-"_)" 0 " $ \t- 0" " $ \t- "
Can it not handle non-number formats like phone numbers, social security numbers, etc?

It could probably be hacked to do so, but it's has not been created for this purposes.
These kind of tasks could be taken up by regular expressions and be far more effective and expressive.
The first example could be simplified to the following
String regex = "^(\\d{3})(\\d{2})(\\d{4})$";
String input = 123456789L + "";
System.out.println(input.replaceAll(regex, "$1-$2-$3")); // 123-45-6789
The second one to the following
String regex = "^(\\d{3})(\\d{3})(\\d{4})$";
String input = 1234567890L + "";
System.out.println(input.replaceAll(regex, "($1)$2-$3")); // (123)456-7890
And so on...

Related

Increment the number part of a String but keeping the character part in Java

I came across several questions but without an answer for my problem.
I have a code camming from data-base in this format: FR000009.
The output should be: FR000010
String original = "FR000009";
String incremented = "FR" + String.format("%0" + (original.length() - 2) + "d",
Integer.parseInt(original.substring(2)) + 1);
System.out.println(incremented);
Here came the difference from other questions: I want to parse the string without the need of hardcoding FR like in the example above. In time there can be different country codes (DE, UK,RO etc).
You need a method where you can pass in the country code and create a new string from the old one.
Your requirement isn't clear. I can't tell if you always want to increment the value, regardless of country code.
I think you need a better abstraction than a String. I don't know what this String is, but I'd recommend a class with a static counter and a method that takes in a country code and returns a String value after incrementing the counter. No parsing needed.
Why not just split between digits and leters:
String input = "FR100109";
String[] splited = input.split("(?<=\\D)(?=\\d)");
int incremented = Integer.parseInt(splited[1]) + 1;
String formated = String.format("%0"+ splited[1].length() + "d", incremented);
System.out.println(splited[0] + formated);
You can use this code by stripping all digits first and then stripping all non-digits:
String original = "FR000009";
String repl = String.format("%s%0" + (original.length() - 2) + "d",
original.replaceFirst("\\d+", ""),
(Integer.valueOf(original.replaceFirst("\\D+", "")) + 1));
//=> "FR000010"
Here:
replaceFirst("\\d+", ""): removes all digits from input, giving us FR
replaceFirst("\\D+", ""): removes all non-digits from input, giving us 000009
Note that if there are always only 2 letters at the start and remaining are digits then you won't even need a regex code, just use substring:
String repl = String.format("%s%0" + (original.length() - 2) + "d",
original.substring(0, 2),
(Integer.valueOf(original.substring(2)) + 1));

Extra java input validation for strings

I want to make this so that short inputs can still be detected, such as "Londo" and "Lon", but want to keep it small and use it without basically copying and pasting the code, any tips? thank you.
if (Menu.answer1.equals("London"))
{
if (location.equals("London")) {
System.out.print(location + " ");
System.out.print(date + " ");
System.out.print(degrees + "C ");
System.out.print(wind + "MPH ");
System.out.print(winddirection + " ");
System.out.print(weather + " ");
System.out.println("");
}
You can use startsWith()
String city = "London";
if (city.startsWith("Lon")) {
// do something
}
Also if you need to check some substring, you can use contains method:
Menu.answer1 = "London";
Menu.answer1.contains("ondo"); // true
If you want to check against a fixed set of alternatives, you may use a list of valid inputs using contains:
List<String> londonNames = Arrays.asList("London", "Londo", "Lon");
if (londonNames.contains(Menu.answer1)) {
...
}
You can use (case-insensitive) regex to do the same, e.g.:
(?)Lon[a-z]{0,3} where
(?) = case insensitivity
Lon = Initial 3 characters
[a-z]{0,3} = any number of alphabets between 0 and 3
Here's an example:
String regex = "(?)Lon[a-z]{0,3}";
System.out.println("London".matches(regex));
System.out.println("Lond".matches(regex));
System.out.println("Lon".matches(regex));
If the underlying problem is that the user can enter one of several names, and you want to allow abbreviations, then a fairly standard approach is to have a table of acceptable names.
Given the user input, loop through the table testing "does the table entry start with the string typed by the user?" (like one of the previous answers here). If yes, then you have a potential match.
Keep looking. If you get a second match then the user input was ambiguous and should be rejected.
As a bonus, you can collect all names that match, and then use them in an error message. ("Pick one of London, Lonfoo, Lonbar").
This approach has the advantage (compared to a long chain of if-then-else logic) of not requiring you to write more code when all you want to do is have more data.
It automatically allows the shortest unique abbreviation, and will adjust when a once-unique abbreviation is no longer unique because of newly-added names.

java parsing array input control

Thanks for checking out my question.
Starting off, the program has the following goal; the user inputs currency formatted as "xD xC xP xH"; the program checks the input is correct and then prints back the 'long' version: "x Dollars, x Cents, x Penny's, x half penny's"
Here I have some code that takes input from user as String currencyIn, splits the string into array tokens, then replaces the D's with Dollars etc and prints the output.
public class parseArray
{
public parseArray()
{
System.out.print('\u000c');
String CurrencyFormat = "xD xS xP xH";
System.out.println("Please enter currency in the following format: \""+CurrencyFormat+"\" where x is any integer");
System.out.println("\nPlease take care to use the correct spacing enter the exact integer plus type of coin\n\n");
Scanner input = new Scanner(System.in);
String currencyIn = input.nextLine();
currencyIn.toUpperCase();
System.out.println("This is the currency you entered: "+currencyIn);
String[] tokens = currencyIn.split(" ");
for (String t : tokens)
{
System.out.println(t);
}
String dollars = tokens[0].replaceAll("D", " Dollars ");
String cents = tokens[1].replaceAll("C", " cents");
String penny = tokens[2].replaceAll("P", " Penny's");
String hPenny = tokens[3].replaceAll("H", " Half penny's");
System.out.println(" "+dollars+ " " +cents+ " " +penny+ " " +hPenny);
input.close();
}
}
Question 1: At the moment the program prints out pretty anything you put in. how do I establish some input control? I've seen this done in textbooks with switch statement and a series of if statements, but were too complicated for me. Would it parse characters using charAt() for each element of the array?
Question 2: Is there a 'better' way to print the output? My friend said converting my 4 strings (dollars, cents, penny's, hpenny's) into elements 0, 1, 2, 3 of a new array (called newArray) and print like this:
System.out.println(Arrays.toString(newArray));
Many thanks in advance.
There is a neat solution, involving Regular Expressions, Streams and some lambdas. Core concept is that we define the input format through a regular expression. We need some sequence of digits, followed by a 'D' or a 'd', followed by a " ", followed by a sequence of digits, followed by a C or c,... I will skip derivation of this pattern, it is explained in the regular expression tutorial I linked above. We will find that
final String regex = "([0-9]+)[D|d]\\ ([0-9]+)[C|c]\\ ([0-9]+)[P|p]\\ ([0-9]+)[H|h]";
satisfies our needs. With this regular expression we can now determine whether our input String has the right format (input.matches(regex)), as well as extract the bits of information we are actually interested in (input.replaceAll(regex, "$1 $2 $3 $4"). Sadly, replaceAll yields another String, but it will contain the four digit sequences we are interested in, divided by a " ". We will use some stream-magic to transform this String into a long[] (where the first cell holds the D-value, the second holds the C-value,...). The final program looks like this:
import java.util.Arrays;
public class Test {
public static void main(String... args) {
final String input = args[0];
final String regex =
"([0-9]+)[D|d]\\ ([0-9]+)[C|c]\\ ([0-9]+)[P|p]\\ ([0-9]+)[H|h]";
if (input.matches(regex) == false) {
throw new IllegalArgumentException("Input is malformed.");
}
long[] values = Arrays.stream(input.replaceAll(regex, "$1 $2 $3 $4").split(" "))
.mapToLong(Long::parseLong)
.toArray();
System.out.println(Arrays.toString(values));
}
}
If you want to have a List<Long> instead a long[] (or a List<Integer> instead of an int[]), you would use
List<Long> values = Arrays.stream(input.replaceAll(regex, "$1 $2 $3 $4").split(" "))
.map(Long::parseLong)
.collect(Collectors.toList());
It is necessary to change mapToLong to map to receive a Stream<Long> instead of a LongStream. I am sure that one could somehow write a custom Collector for LongStream to transform it into a List<Long>, but I found this solution more readable and reliable (after all, the Collector used comes from Oracle, I trust they test their code extensively).
Here is some example call:
$> java Test "10D 9c 8p 7H"
[10, 9, 8, 7]
$> java Test "10E 9C 8P 7H"
Exception in thread "main" java.lang.IllegalArgumentException: Input is malformed.
at Test.main(Test.java:10)
$> java Test "10D 9C 8P 7H 10D 9C 8P 7H"
Exception in thread "main" java.lang.IllegalArgumentException: Input is malformed.
at Test.main(Test.java:10)
Question1
You can actually check if the input is what it's supposed to be with simple checks. For example, you can check the first element like this:
if(tokens[0].charAt(1).equals("D"))
return true;
else
return false;
Another way to check if the input is correct is by using Regular Expressions, but I assume you are a beginner and this is too much trouble for you, although it is the better way. So I leave it to you to look through it later.
Question2
You can actually listen to your friend and do as they said. You can write it as follows:
for(int i = 0; i < 4; i++)
System.out.print(" " + tokens[i])
System.out.println();
Or you may use
System.out.println(Arrays.toString(newArray));
And you have saved newArray like this:
newArray[0] = " " + tokens[0];
you could use the .equals() method to see if what a user has typed in matches what you have
if (currencyIn.equals("CurrencyFormat"))
{
...
}
this is probably the simplest way i can think of!

Parsing & Replacing Values in a String

Questions like this one have been answered but none helped me understand and decide the best suited way to do this in my case.
The idea:
Input: 15k+5b-1m
Ouput: 15000+5000000000-1000000
Basically replacing k by 1,000 - m by 1,000,000 and b by 1,000,000,000 and multiply it to the value it is attached to.
How I thought I'd do it:
Using 2 StringTokenizer, one to parse math signs +,-,*,/ and one to parse
letter k,m,b that I call on every element the first parser got.
So if we apply the algorithm we'd have for my example:
Str Input = 15k+5b-1m
StringTokenizer math_token= new StringTokenizer(source, Input);
while (math_token.hasMoreTokens())
{
while(math_token.hasMoreElements())
{
Str token_value = math_token.nextElement();
parse_letters(token_value) and change values...
}
math_token.nextToken();
format stuff for the final string
}
So it goes like:
15k -> 15 -> 15000
If I understand your question, then you could replace b with nine zeros m with six zeros and k with three zeros. Also, by convention, Java variable names start with a lower-case letter. Something like,
String input = "15k+5b-1m";
input = input.replace("b", "000000000").replace("m", "000000")
.replace("k", "000");
System.out.println(input);
which outputs (as requested)
15000+5000000000-1000000

comparing array strings

The user enters an array of numbers such as "123456789"
and then the user is supposed to enter a string of commands such as "PE"
and my program will check each character in the string.
P = Remove the last number entered, which is 9
E = Prints out the final result.
To this point everything was working fine.
But my problem is that I have to be able to read the command when the user inputs "P(any number)", and I have to place that number at the end of the array of numbers.
So if it was P(4), the result would be "1234567894".
How can I do this ?
This is what I have right now for P and E.
if (commandList.get(x).equals("P(")) {
JOptionPane.showMessageDialog(null, "HI");
}
else if (commandList.get(x).equals("P")) {
strList.remove(strList.size()-1);
x++;
}
As far as I understand, your problem is to extract the 'digit' from the string "P(digit)" ?
Well you have to parse the input string, e.g., by searching for bounding characters, here '(' and ')'. For example by something like that:
String s = "P(3)";
String number = s.substring(s.indexOf("(") + 1, s.indexOf(")"));
strList.append(number);
But this would also accept anything within the bracktes, e.g., "foooo" from "P(foooo)", and it would crash if ')' cannot be found, e.g., s = "P(123", and it would accept "P(3)blah54" which is strictly spoken invalid. To improve your parser, you can use regular expressions, e.g., to check if the input is exactly of the form "P(2)" for exactly a single digit, you can use
String s = "P(3)";
if (!s.matches("P\\(\\d\\)"))
throw new RuntimeException("invalid input format: " + s);
String number = s.substring(s.indexOf("(") + 1, s.indexOf(")"));
strList.append(number);
If you explicitly want to cast the digit to an int, you might have a look at Integer.parseInt(...), e.g.,
int i = Integer.parseInt(number);

Categories