Detect Chinese character in java - java

Using Java how to detect if a String contains Chinese characters?
String chineseStr = "已下架" ;
if (isChineseString(chineseStr)) {
System.out.println("The string contains Chinese characters");
}else{
System.out.println("The string contains Chinese characters");
}
Can you please help me to solve the problem?

Now Character.isIdeographic(int codepoint) would tell wether the codepoint is a CJKV (Chinese, Japanese, Korean and Vietnamese) ideograph.
Nearer is using Character.UnicodeScript.HAN.
So:
System.out.println(containsHanScript("xxx已下架xxx"));
public static boolean containsHanScript(String s) {
for (int i = 0; i < s.length(); ) {
int codepoint = s.codePointAt(i);
i += Character.charCount(codepoint);
if (Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HAN) {
return true;
}
}
return false;
}
Or in java 8:
public static boolean containsHanScript(String s) {
return s.codePoints().anyMatch(
codepoint ->
Character.UnicodeScript.of(codepoint) == Character.UnicodeScript.HAN);
}

A more direct approach:
if ("粽子".matches("[\\u4E00-\\u9FA5]+")) {
System.out.println("is Chinese");
}
If you also need to catch rarely used and exotic characters then you'll need to add all the ranges: What's the complete range for Chinese characters in Unicode?

You can try with Google API or Language Detection API
Language Detection API contains simple demo. You can try it first.

Related

Can I check a String for characters other than specific ones?

I am writing a Java program that can convert an inputted Roman Numeral into a Short, and I want it to be able to recognize and ask for input again when any letter has been inputted besides a Roman Numeral (I, V, X, L, C, D, and M).
Is there a method similar to .contains(), but with the opposite function?
Or do I have to check each individual letter with some kind of loop?
Well of course, you need some type of filter to test against the input.
One solution could be to use a string that contains all the possible valid characters in the input and then return false if a character wasn't found in the filter.
public class HelloWorld
{
public static boolean filter(String test, String filter) {
for(int i = 0; i < test.length(); i++) {
if (filter.indexOf(test.charAt(i)) == -1) {
return false;
}
}
return true;
}
// arguments are passed using the text field below this editor
public static void main(String[] args)
{
System.out.println(filter("XDQX", "XDQ"));
}
}
I suggest you use a regular expression to check whether the input is a Roman numeral. You can find a regular expression for this problem here. Use String#matches() to determine whether your input matches the regex.
if(!input.matches("^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$")) { // input is the String the user entered
// handle invalid input here
}
Just testing for valid characters, not for a valid sequence, can be done with contains:
boolean roman (String s)
{
for (char c: s.toCharArray())
if (! "IVXCLDM".contains(""+c))
return false;
return true;
}
However, I would prefer a regular expression
boolean roman (String s)
{
return s.matches ("[IVXCLDM]+");
}
which means any number(+) of characters from that Set, at least one.

How to detect if a string contains atleast one char of a particular language?

I am creating an Android application where I have a string. I want to check whether this string contains at least one character that belongs to Hindi language or not.
It does not matter in which language the String is, but if it has atleast one character that is in Hindi language, my function needs to be called.
One of the ways of doing so is comparing each character of the string with all the unicodes of Hindi language. But wont that be too time consuming? For example 50 character of string and 50 unicode will end up with 2500 comparisons already.
What can be the most optimum solution to this?
I think of these two methods
Method 1
boolean isHindi = false;
for (char c: myString.toCharArray()) {
if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.DEVANAGARI) {
isHindi = true;
break;
}
}
Method 2
boolean isHindi = false;
for (int k = 0; k < Character.codePointCount(myString, 0, myString.length()); k++) {
int c = myString.codePointAt(k);
if (c >= 0x0900 && c <= 0x097F) { //Hindi uni-codes are within this range
isHindi = true;
break;
}
}
If you are using java-8, you could do:
boolean isHindi =
myString.chars().anyMatch(c -> Character.UnicodeBlock.of(c) == Character.UnicodeBlock.DEVANAGARI);
You can also do regex matching. Here is a sample code
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HindiDetctionDemo {
public static void main(String args[]) {
Pattern hindiFirstCharMatchPattern = Pattern.compile("[\\u0900-\\u097F].*");
Matcher hindiFirstCharMatcher = hindiFirstCharMatchPattern.matcher("ok ");
if(hindiFirstCharMatcher.matches()) {
System.out.println("found");
} else {
System.out.println("could not find.");
}
}
}
Note about regex
[\u0900-\u097F] is matcher for hindi characters.
.* is appended so that matching stops after first match.

Convert String to Number, Java

Edit: Clarification convert any valid number encoding from a string to a number
How does one convert a string to a number, say just for integers, for all accepted integer formats, particularly the ones that throw NumberFormatException under Integer.parseInt. For example, the code
...
int i = 0xff;
System.out.println(i);
String s = "0xff";
System.out.println( Integer.parseInt(s) );
....
Will throw a NumberFormatException on the fourth line, even though the string is clearly a valid encoding for a hexadecimal integer. We can assume that we already know that the encoding is a valid number, say by checking it against a regex. It would be nice to also check for overflow (like Integer.parseInt does), but it would be okay if that has to be done as a separate step.
I could loop through every digit and manually calculate the composite, but that would pretty difficult. Is there a better way?
EDIT: a lot of people are answering this for hexidecimal, which is great, but not completely what I was asking (it's my fault, I used hexidecimal as the example). I'm wondering if there's a way to decode all valid java numbers. Long.decode is definitely great for just catching hex, but it fails on
222222L
which is a perfectly valid long. Do I have to catch for every different number format separately? I'm assuming you've used a regex to tell what category of number it is, i.e, distinguish floats, integers, etc.
You could do
System.out.println(Integer.decode(s));
You need to specify the base of the number you are trying to parse:
Integer.parseInt(s,16);
This will fail if you have that "0x" starting it off so you could just add a check:
if (s.startsWith("0x")) {
s = s.substring(2);
}
Integer.parseInt(s,16);
EDIT
In response to the information that this was not a hex specific question I would recommend writing your own method to parse out all the numbers formats you like and build in on top of Integer.decode which can save you from having to handle a couple of cases.
I would say use regex or create your own methods to validate other formats:
public static int manualDecode(String s) throws NumberFormatException {
// Match against #####L long format
Pattern p = Pattern.compile("\\d+L"); // Matches ########L
Matcher m = p.matcher(s);
if (m.matches()) {
return Integer.decode(s.substring(0,s.length()-1));
}
// Match against that weird underscore format
p = Pattern.compile("(\\d{1,3})_((\\d{3})_)*?(\\d{3})"); // Matches ###_###_###_###_###
m = p.matcher(s);
if (m.matches()) {
String reformattedString = "";
char c;
for (int i = 0; i < s.length(); i++) {
c = s.charAt(i);
if ( c >= '0' && c <= '9') {
reformattedString += c;
}
}
return Integer.decode(reformattedString);
}
// Add as many more as you wish
throw new NumberFormatException();
}
public int parseIntExtended(String s) {
try {
return Integer.decode(s);
} catch (NumberFormatException e) {
return manualDecode(s);
}
}
Integer.decode should do the trick:
public class a{
public static void main(String[] args){
String s="0xff";
System.out.println(Integer.decode(s));
}
}
You can try using BigInteger also but sill you have to remove 0x first or replace x from 0
int val = new BigInteger("ff", 16).intValue(); // output 255

Java: How do I check the if a char at the nth position of a string is a letter or if is a number?

Let's say I have this string: "abcd123fx".
Now, I want to make a method which checks (in order) if "a","b","c","d" etc is a number and if not, returns false. I don't know how to handle the n-th position of char and for each char, in order.
You can check if a character is a letter of number with teh Character class.
String text = ...
char ch = texct.charAt(nth);
if (Character.isLetter(ch)) {
// is a letter
} else if (Character.isDigit(ch)) {
// is a digit
}
Note: these method support characters in different blocks of the unicode. e.g. it will accept characters in Arabic or Korean.
Check the documentation. You can use charAt function.
if (Character.isLetter(yourString.charAt(index)))
// ... Letter
if (Character.isDigit(yourString.charAt(index)))
// ... Number
Check this page
Well there are a few ways you could do this. The simplest would probably be something along the lines of:
Character.isDigit(someString.charAt(x))
or a regex way would be someString.substring(x,x).matches("[0-9]")
To get the nth character of a string you should use charAt, the you should use the Charachter's isLetterOrDigit.
Usually, when you face these problems, you should search the javadoc looking for suitable methods.
Check out the Java tutorials on oracle.com for more information.
Specifically for this subject:
Characters, specifically the Character.isLetter(char ch) and Character.isDigit(char ch) methods
Strings and Manipulating Characters in a String, the simplest method is String.charAt(int index)
- As you have said that you are a newbie, i won't make this complicated using Regex, but will use inbuilt Java functionalities to answer this.
- First use subString() method to get the "abcd" part of the String, then use toCharArray() method to break the String into char elements, then use Character class's isDigit() method to know whether its a digit or not.
Eg:
public class T1 {
public static void main(String[] args){
String s = "abcd123fx";
String str = s.substring(0,4);
System.out.println(str);
char[] cArr = str.toCharArray();
for(char a :cArr){
if(Character.isDigit(a)){
System.out.println(a+" is a digit");
}else{
System.out.println(a+" is not a digit");
}
}
}
}
This might help you
public static boolean isNumeric(String str) {
return str.matches("-?\\d+(.\\d+)?");
}
public static void main(String[] args){
System.out.println(isNumeric("abcd123fx"));
}
If you have a numeric string it will return true else false
public static void main(String[] args){
System.out.println(checkNumber("123a44"));
}
public static boolean checkNumber(String s){
for(int i = 0; i < s.length(); i++){
if(Character.isDigit(s.charAt(i))){
continue;
}
else{
return false;
}
}
return true;
}
You can also have a look into the ASCII table
Depending on this you can write a method:
private boolean isNumber(char a) {
int i = a;
if(i >= 48 && i <=57)
return true;
else
return false;
}
// now you can look by a String
private void checkString() {
String x = "abcd123fx ";
for(char counter : x.toCharArray())
System.out.println(isNumber(counter));
}

Determine if a String is a number and convert in Java?

I know variants of this question have been asked frequently before (see here and here for instance), but this is not an exact duplicate of those.
I would like to check if a String is a number, and if so I would like to store it as a double. There are several ways to do this, but all of them seem inappropriate for my purposes.
One solution would be to use Double.parseDouble(s) or similarly new BigDecimal(s). However, those solutions don't work if there are commas present (so "1,234" would cause an exception). I could of course strip out all commas before using these techniques, but that would seem to pose loads of problems in other locales.
I looked at Apache Commons NumberUtils.isNumber(s), but that suffers from the same comma issue.
I considered NumberFormat or DecimalFormat, but those seemed far too lenient. For instance, "1A" is formatted to "1" instead of indicating that it's not a number. Furthermore, something like "127.0.0.1" will be counted as the number 127 instead of indicating that it's not a number.
I feel like my requirements aren't so exotic that I'm the first to do this, but none of the solutions does exactly what I need. I suppose even I don't know exactly what I need (otherwise I could write my own parser), but I know the above solutions do not work for the reasons indicated. Does any solution exist, or do I need to figure out precisely what I need and write my own code for it?
Sounds quite weird, but I would try to follow this answer and use java.util.Scanner.
Scanner scanner = new Scanner(input);
if (scanner.hasNextInt())
System.out.println(scanner.nextInt());
else if (scanner.hasNextDouble())
System.out.println(scanner.nextDouble());
else
System.out.println("Not a number");
For inputs such as 1A, 127.0.0.1, 1,234, 6.02e-23 I get the following output:
Not a number
Not a number
1234
6.02E-23
Scanner.useLocale can be used to change to the desired locale.
You can specify the Locale that you need:
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
double myNumber = nf.parse(myString).doubleValue();
This should work in your example since German Locale has commas as decimal separator.
You can use the ParsePosition as a check for complete consumption of the string in a NumberFormat.parse operation. If the string is consumed, then you don't have a "1A" situation. If not, you do and can behave accordingly. See here for a quick outline of the solution and here for the related JDK bug that is closed as wont fix because of the ParsePosition option.
Unfortunately Double.parseDouble(s) or new BigDecimal(s) seem to be your best options.
You cite localisation concerns, but unfortunately there is no way reliably support all locales w/o specification by the user anyway. It is just impossible.
Sometimes you can reason about the scheme used by looking at whether commas or periods are used first, if both are used, but this isn't always possible, so why even try? Better to have a system which you know works reliably in certain situations than try to rely on one which may work in more situations but can also give bad results...
What does the number 123,456 represent? 123456 or 123.456?
Just strip commas, or spaces, or periods, depending on locale specified by user. Default to stripping spaces and commas. If you want to make it stricter, only strip commas OR spaces, not both, and only before the period if there is one. Also should be pretty easy to check manually if they are spaced properly in threes. In fact a custom parser might be easiest here.
Here is a bit of a proof of concept. It's a bit (very) messy but I reckon it works, and you get the idea anyways :).
public class StrictNumberParser {
public double parse(String numberString) throws NumberFormatException {
numberString = numberString.trim();
char[] numberChars = numberString.toCharArray();
Character separator = null;
int separatorCount = 0;
boolean noMoreSeparators = false;
for (int index = 1; index < numberChars.length; index++) {
char character = numberChars[index];
if (noMoreSeparators || separatorCount < 3) {
if (character == '.') {
if (separator != null) {
throw new NumberFormatException();
} else {
noMoreSeparators = true;
}
} else if (separator == null && (character == ',' || character == ' ')) {
if (noMoreSeparators) {
throw new NumberFormatException();
}
separator = new Character(character);
separatorCount = -1;
} else if (!Character.isDigit(character)) {
throw new NumberFormatException();
}
separatorCount++;
} else {
if (character == '.') {
noMoreSeparators = true;
} else if (separator == null) {
if (Character.isDigit(character)) {
noMoreSeparators = true;
} else if (character == ',' || character == ' ') {
separator = new Character(character);
} else {
throw new NumberFormatException();
}
} else if (!separator.equals(character)) {
throw new NumberFormatException();
}
separatorCount = 0;
}
}
if (separator != null) {
if (!noMoreSeparators && separatorCount != 3) {
throw new NumberFormatException();
}
numberString = numberString.replaceAll(separator.toString(), "");
}
return Double.parseDouble(numberString);
}
public void testParse(String testString) {
try {
System.out.println("result: " + parse(testString));
} catch (NumberFormatException e) {
System.out.println("Couldn't parse number!");
}
}
public static void main(String[] args) {
StrictNumberParser p = new StrictNumberParser();
p.testParse("123 45.6");
p.testParse("123 4567.8");
p.testParse("123 4567");
p.testParse("12 45");
p.testParse("123 456 45");
p.testParse("345.562,346");
p.testParse("123 456,789");
p.testParse("123,456,789");
p.testParse("123 456 789.52");
p.testParse("23,456,789");
p.testParse("3,456,789");
p.testParse("123 456.12");
p.testParse("1234567.8");
}
}
EDIT: obviously this would need to be extended for recognising scientific notation, but this should be simple enough, especially as you don't have to actually validate anything after the e, you can just let parseDouble fail if it is badly formed.
Also might be a good idea to properly extend NumberFormat with this. have a getSeparator() for parsed numbers and a setSeparator for giving desired output format... This sort of takes care of localisation, but again more work would need to be done to support ',' for decimals...
Not sure if it meets all your requirements, but the code found here might point you in the right direction?
From the article:
To summarize, the steps for proper input processing are:
Get an appropriate NumberFormat and define a ParsePosition variable.
Set the ParsePosition index to zero.
Parse the input value with parse(String source, ParsePosition parsePosition).
Perform error operations if the input length and ParsePosition index value don't match or if the parsed Number is null.
Otherwise, the value passed validation.
This is an interesting problem. But perhaps it is a little open-ended? Are you looking specifically to identify base-10 numbers, or hex, or what? I'm assuming base-10. What about currency? Is that important? Or is it just numbers.
In any case, I think that you can use the deficiencies of Number format to your advantage. Since you no that something like "1A", will be interpreted as 1, why not check the result by formatting it and comparing against the original string?
public static boolean isNumber(String s){
try{
Locale l = Locale.getDefault();
DecimalFormat df = new DecimalFormat("###.##;-##.##");
Number n = df.parse(s);
String sb = df.format(n);
return sb.equals(s);
}
catch(Exception e){
return false;
}
}
What do you think?
This is really interesting, and I think people are trying to overcomplicate it. I would really just break this down by rules:
1) Check for scientific notation (does it match the pattern of being all numbers, commas, periods, -/+ and having an 'e' in it?) -- if so, parse however you want
2) Does it match the regexp for valid numeric characters (0-9 , . - +) (only 1 . - or + allowed)
if so, strip out everything that's not a digit and parse appropriately, otherwise fail.
I can't see a shortcut that's going to work here, just take the brute force approach, not everything in programming can be (or needs to be) completely elegant.
My understanding is that you want to cover Western/Latin languages while retaining as much strict interpretation as possible. So what I'm doing here is asking DecimalFormatSymbols to tell me what the grouping, decimal, negative, and zero separators are, and swapping them out for symbols Double will recognize.
How does it perform?
In the US, it rejects: "1A", "127.100.100.100"
and accepts "1.47E-9"
In Germany it still rejects "1A"
It ACCEPTS "1,024.00" but interprets it correctly as 1.024. Likewise, it accepts "127.100.100.100" as 127100100100.0
In fact, the German locale correctly identifies and parses "1,47E-9"
Let me know if you have any trouble in a different locale.
import java.util.Locale;
import java.text.DecimalFormatSymbols;
public class StrictNumberFormat {
public static boolean isDouble(String s, Locale l) {
String clean = convertLocaleCharacters(s,l);
try {
Double.valueOf(clean);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
public static double doubleValue(String s, Locale l) {
return Double.valueOf(convertLocaleCharacters(s,l));
}
public static boolean isDouble(String s) {
return isDouble(s,Locale.getDefault());
}
public static double doubleValue(String s) {
return doubleValue(s,Locale.getDefault());
}
private static String convertLocaleCharacters(String number, Locale l) {
DecimalFormatSymbols symbols = new DecimalFormatSymbols(l);
String grouping = getUnicodeRepresentation( symbols.getGroupingSeparator() );
String decimal = getUnicodeRepresentation( symbols.getDecimalSeparator() );
String negative = getUnicodeRepresentation( symbols.getMinusSign() );
String zero = getUnicodeRepresentation( symbols.getZeroDigit() );
String clean = number.replaceAll(grouping, "");
clean = clean.replaceAll(decimal, ".");
clean = clean.replaceAll(negative, "-");
clean = clean.replaceAll(zero, "0");
return clean;
}
private static String getUnicodeRepresentation(char ch) {
String unicodeString = Integer.toHexString(ch); //ch implicitly promoted to int
while(unicodeString.length()<4) unicodeString = "0"+unicodeString;
return "\\u"+unicodeString;
}
}
You're best off doing it manually. Figure out what you can accept as a number and disregard everything else:
import java.lang.NumberFormatException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class ParseDouble {
public static void main(String[] argv) {
String line = "$$$|%|#|1A|127.0.0.1|1,344|95|99.64";
for (String s : line.split("\\|")) {
try {
System.out.println("parsed: " +
any2double(s)
);
}catch (NumberFormatException ne) {
System.out.println(ne.getMessage());
}
}
}
public static double any2double(String input) throws NumberFormatException {
double out =0d;
Pattern special = Pattern.compile("[^a-zA-Z0-9\\.,]+");
Pattern letters = Pattern.compile("[a-zA-Z]+");
Pattern comma = Pattern.compile(",");
Pattern allDigits = Pattern.compile("^[0-9]+$");
Pattern singleDouble = Pattern.compile("^[0-9]+\\.[0-9]+$");
Matcher[] goodCases = new Matcher[]{
allDigits.matcher(input),
singleDouble.matcher(input)
};
Matcher[] nanCases = new Matcher[]{
special.matcher(input),
letters.matcher(input)
};
// maybe cases
if (comma.matcher(input).find()){
out = Double.parseDouble(
comma.matcher(input).replaceFirst("."));
return out;
}
for (Matcher m : nanCases) {
if (m.find()) {
throw new NumberFormatException("Bad input "+input);
}
}
for (Matcher m : goodCases) {
if (m.find()) {
try {
out = Double.parseDouble(input);
return out;
} catch (NumberFormatException ne){
System.out.println(ne.getMessage());
}
}
}
throw new NumberFormatException("Could not parse "+input);
}
}
If you set your locale right, built in parseDouble will work with commas. Example is here.
I think you've got a multi step process to handle here with a custom solution, if you're not willing to accept the results of DecimalFormat or the answers already linked.
1) Identify the decimal and grouping separators. You might need to identify other format symbols (such as scientific notation indicators).
http://download.oracle.com/javase/1.4.2/docs/api/java/text/DecimalFormat.html#getDecimalFormatSymbols()
2) Strip out all grouping symbols (or craft a regex, be careful of other symbols you accept such as the decimal if you do). Then strip out the first decimal symbol. Other symbols as needed.
3) Call parse or isNumber.
One of the easy hacks would be to use replaceFirst for String you get and check the new String whether it is a double or not. In case it's a double - convert back (if needed)
If you want to convert some string number which is comma separated decimal to double, you could use DecimalSeparator + DecimalFormalSymbols:
final double strToDouble(String str, char separator){
DecimalFormatSymbols s = new DecimalFormatSymbols();
s.setDecimalSeparator(separator);
DecimalFormat df = new DecimalFormat();
double num = 0;
df.setDecimalFormatSymbols(s);
try{
num = ((Double) df.parse(str)).doubleValue();
}catch(ClassCastException | ParseException ex){
// if you want, you could add something here to
// indicate the string is not double
}
return num;
}
well, lets test it:
String a = "1.2";
String b = "2,3";
String c = "A1";
String d = "127.0.0.1";
System.out.println("\"" + a + "\" = " + strToDouble(a, ','));
System.out.println("\"" + a + "\" (with '.' as separator) = "
+ strToDouble(a, '.'));
System.out.println("\"" + b + "\" = " + strToDouble(b, ','));
System.out.println("\"" + c + "\" = " + strToDouble(c, ','));
System.out.println("\"" + d + "\" = " + strToDouble(d, ','));
if you run the above code, you'll see:
"1.2" = 0.0
"1.2" (with '.' as separator) = 1.2
"2,3" = 2.3
"A1" = 0.0
"127.0.0.1" = 0.0
This will take a string, count its decimals and commas, remove commas, conserve a valid decimal (note that this is based on US standardization - in order to handle 1.000.000,00 as 1 million this process would have to have the decimal and comma handling switched), determine if the structure is valid, and then return a double. Returns null if the string could not be converted. Edit: Added support for international or US. convertStoD(string,true) for US, convertStoD(string,false) for non US. Comments are now for US version.
public double convertStoD(string s,bool isUS){
//string s = "some string or number, something dynamic";
bool isNegative = false;
if(s.charAt(0)== '-')
{
s = s.subString(1);
isNegative = true;
}
string ValidNumberArguements = new string();
if(isUS)
{
ValidNumberArguements = ",.";
}else{
ValidNumberArguements = ".,";
}
int length = s.length;
int currentCommas = 0;
int currentDecimals = 0;
for(int i = 0; i < length; i++){
if(s.charAt(i) == ValidNumberArguements.charAt(0))//charAt(0) = ,
{
currentCommas++;
continue;
}
if(s.charAt(i) == ValidNumberArguements.charAt(1))//charAt(1) = .
{
currentDec++;
continue;
}
if(s.charAt(i).matches("\D"))return null;//remove 1 A
}
if(currentDecimals > 1)return null;//remove 1.00.00
string decimalValue = "";
if(currentDecimals > 0)
{
int index = s.indexOf(ValidNumberArguements.charAt(1));
decimalValue += s.substring(index);
s = s.substring(0,index);
if(decimalValue.indexOf(ValidNumberArguements.charAt(0)) != -1)return null;//remove 1.00,000
}
int allowedCommas = (s.length-1) / 3;
if(currentCommas > allowedCommas)return null;//remove 10,00,000
String[] NumberParser = s.split(ValidNumberArguements.charAt(0));
length = NumberParser.length;
StringBuilder returnString = new StringBuilder();
for(int i = 0; i < length; i++)
{
if(i == 0)
{
if(NumberParser[i].length > 3 && length > 1)return null;//remove 1234,0,000
returnString.append(NumberParser[i]);
continue;
}
if(NumberParser[i].length != 3)return null;//ensure proper 1,000,000
returnString.append(NumberParser[i]);
}
returnString.append(decimalValue);
double answer = Double.parseDouble(returnString);
if(isNegative)answer *= -1;
return answer;
}
This code should handle most inputs, except IP addresses where all groups of digits are in three's (ex: 255.255.255.255 is valid, but not 255.1.255.255). It also doesn't support scientific notation
It will work with most variants of separators (",", "." or space). If more than one separator is detected, the first is assumed to be the thousands separator, with additional checks (validity etc.)
Edit: prevDigit is used for checking that the number uses thousand separators correctly. If there are more than one group of thousands, all but the first one must be in groups of 3. I modified the code to make it clearer so that "3" is not a magic number but a constant.
Edit 2: I don't mind the down votes much, but can someone explain what the problem is?
/* A number using thousand separator must have
groups of 3 digits, except the first one.
Numbers following the decimal separator can
of course be unlimited. */
private final static int GROUP_SIZE=3;
public static boolean isNumber(String input) {
boolean inThousandSep = false;
boolean inDecimalSep = false;
boolean endsWithDigit = false;
char thousandSep = '\0';
int prevDigits = 0;
for(int i=0; i < input.length(); i++) {
char c = input.charAt(i);
switch(c) {
case ',':
case '.':
case ' ':
endsWithDigit = false;
if(inDecimalSep)
return false;
else if(inThousandSep) {
if(c != thousandSep)
inDecimalSep = true;
if(prevDigits != GROUP_SIZE)
return false; // Invalid use of separator
}
else {
if(prevDigits > GROUP_SIZE || prevDigits == 0)
return false;
thousandSep = c;
inThousandSep = true;
}
prevDigits = 0;
break;
default:
if(Character.isDigit(c)) {
prevDigits++;
endsWithDigit = true;
}
else {
return false;
}
}
}
return endsWithDigit;
}
Test code:
public static void main(String[] args) {
System.out.println(isNumber("100")); // true
System.out.println(isNumber("100.00")); // true
System.out.println(isNumber("1,5")); // true
System.out.println(isNumber("1,000,000.00.")); // false
System.out.println(isNumber("100,00,2")); // false
System.out.println(isNumber("123.123.23.123")); // false
System.out.println(isNumber("123.123.123.123")); // true
}

Categories