ChatGPT解决这个技术问题 Extra ChatGPT

Java String - See if a string contains only numbers and not letters

I have a string that I load throughout my application, and it changes from numbers to letters and such. I have a simple if statement to see if it contains letters or numbers but, something isn't quite working correctly. Here is a snippet.

String text = "abc"; 
String number; 

if (text.contains("[a-zA-Z]+") == false && text.length() > 2) {
    number = text; 
}

Although the text variable does contain letters, the condition returns as true. The and && should eval as both conditions having to be true in order to process the number = text;

==============================

Solution:

I was able to solve this by using this following code provided by a comment on this question. All other post are valid as well!

What I used that worked came from the first comment. Although all the example codes provided seems to be valid as well!

String text = "abc"; 
String number; 

if (Pattern.matches("[a-zA-Z]+", text) == false && text.length() > 2) {
    number = text; 
}
contains does not take a regexp as input. Use either matches("\\d{2,}") or try with a Pattern and Matcher
Can the string have a decimal value or only integer values?
Why are you checking text.length() > 2? What's the reason?
@RedHatcc Pattern.matches("[a-zA-Z]+", text) == false can be simplified to !Pattern.matches("[a-zA-Z]+", text)
Using java streaming API boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x)); form Max Malysh Post.

u
unwichtich

If you'll be processing the number as text, then change:

if (text.contains("[a-zA-Z]+") == false && text.length() > 2){

to:

if (text.matches("[0-9]+") && text.length() > 2) {

Instead of checking that the string doesn't contain alphabetic characters, check to be sure it contains only numerics.

If you actually want to use the numeric value, use Integer.parseInt() or Double.parseDouble() as others have explained below.

As a side note, it's generally considered bad practice to compare boolean values to true or false. Just use if (condition) or if (!condition).


You probably want to add anchors (e.g. ^[0-9]+$) otherwise abc123def will be considered a number.
I don't think that's required. matches() returns true if and only if it's a complete match from beginning to end.
"^-?\d+\.?\d*$" will compare the whole string and only match if it is a valid number (negatives and decimals included). For example, it will match 1, 10, 1.0, -1, -1.0, etc. It'll also match on "1." but that can often be parsed anyway.
There is no need to call && (text.length() > 2). Everything can be checked in regex pattern: if (text.matches("[0-9]{3,}")
What about commas or dots for numbers that are not integers?
h
hannojg

You can also use NumberUtil.isCreatable(String str) from Apache Commons


I don't think NumberUtil.isCreatable(String str) is correct to use for what the original question asks for. E.g., NumberUtil.isCreatable( "09" ) returns false, even though "09" contains only numbers.
even NumberUtils.isCreatable("068907") will return false
t
tokhi

This is how I would do it:

if(text.matches("^[0-9]*$") && text.length() > 2){
    //...
}

The $ will avoid a partial match e.g; 1B.


I don't need the text.length() > 2 part, so I just replaced ^[0-9]*$ by ^[0-9]+$ to be sure I have at least one number.
text.matches("^[0-9]*$") is the same as text.matches("[0-9]*").
A
Aman Kumar Gupta

In order to simply check the string that it contains only ALPHABETS use the following code :

if (text.matches("[a-zA-Z]+"){
   // your operations
}

In order to simply check the string that it contains only NUMBER use the following code :

if (text.matches("[0-9]+"){
   // your operations
}

Hope this will help to someone!


A
Anton R

Performance-wise parseInt and such are much worser than other solutions, because at least require exception handling.

I've run jmh tests and have found that iterating over String using charAt and comparing chars with boundary chars is the fastest way to test if string contains only digits.

JMH testing

Tests compare performance of Character.isDigit vs Pattern.matcher().matches vs Long.parseLong vs checking char values.

These ways can produce different result for non-ascii strings and strings containing +/- signs.

Tests run in Throughput mode (greater is better) with 5 warmup iterations and 5 test iterations.

Results

Note that parseLong is almost 100 times slower than isDigit for first test load.

## Test load with 25% valid strings (75% strings contain non-digit symbols)

Benchmark       Mode  Cnt  Score   Error  Units
testIsDigit    thrpt    5  9.275 ± 2.348  ops/s
testPattern    thrpt    5  2.135 ± 0.697  ops/s
testParseLong  thrpt    5  0.166 ± 0.021  ops/s

## Test load with 50% valid strings (50% strings contain non-digit symbols)

Benchmark              Mode  Cnt  Score   Error  Units
testCharBetween       thrpt    5  16.773 ± 0.401  ops/s
testCharAtIsDigit     thrpt    5  8.917 ± 0.767  ops/s
testCharArrayIsDigit  thrpt    5  6.553 ± 0.425  ops/s
testPattern           thrpt    5  1.287 ± 0.057  ops/s
testIntStreamCodes    thrpt    5  0.966 ± 0.051  ops/s
testParseLong         thrpt    5  0.174 ± 0.013  ops/s
testParseInt          thrpt    5  0.078 ± 0.001  ops/s

Test suite

@State(Scope.Benchmark)
public class StringIsNumberBenchmark {
    private static final long CYCLES = 1_000_000L;
    private static final String[] STRINGS = {"12345678901","98765432177","58745896328","35741596328", "123456789a1", "1a345678901", "1234567890 "};
    private static final Pattern PATTERN = Pattern.compile("\\d+");

    @Benchmark
    public void testPattern() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = PATTERN.matcher(s).matches();
            }
        }
    }

    @Benchmark
    public void testParseLong() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                try {
                    Long.parseLong(s);
                    b = true;
                } catch (NumberFormatException e) {
                    // no-op
                }
            }
        }
    }

    @Benchmark
    public void testCharArrayIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (char c : s.toCharArray()) {
                    b = Character.isDigit(c);
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testCharAtIsDigit() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    b = Character.isDigit(s.charAt(j));
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }

    @Benchmark
    public void testIntStreamCodes() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                b = s.chars().allMatch(c -> c > 47 && c < 58);
            }
        }
    }

    @Benchmark
    public void testCharBetween() {
        for (int i = 0; i < CYCLES; i++) {
            for (String s : STRINGS) {
                boolean b = false;
                for (int j = 0; j < s.length(); j++) {
                    char charr = s.charAt(j);
                    b = '0' <= charr && charr <= '9';
                    if (!b) {
                        break;
                    }
                }
            }
        }
    }
}

Updated on Feb 23, 2018

Add two more cases - one using charAt instead of creating extra array and another using IntStream of char codes

Add immediate break if non-digit found for looped test cases

Return false for empty string for looped test cases

Updated on Feb 23, 2018

Add one more test case (the fastest!) that compares char value without using stream


If you look at the code of toCharArray, it is allocating a char array and copying the chars (i think that could be expensive). What about if you just iterate the string using an index and charAt, would it be faster? Would be interesting also if you could add the solution from Andy to your tests: boolean isNum = text.chars().allMatch(c -> c >= 48 && c <= 57)
A
Abdull

Apache Commons Lang provides org.apache.commons.lang.StringUtils.isNumeric(CharSequence cs), which takes as an argument a String and checks if it consists of purely numeric characters (including numbers from non-Latin scripts). That method returns false if there are characters such as space, minus, plus, and decimal separators such as comma and dot.

Other methods of that class allow for further numeric checks.


A
Andy

boolean isNum = text.chars().allMatch(c -> c >= 48 && c <= 57)


to reduce magic numbers, you could compare as follows: boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
U
Unheilig

Below regexs can be used to check if a string has only number or not:

if (str.matches(".*[^0-9].*")) or if (str.matches(".*\\D.*"))

Both conditions above will return true if String containts non-numbers. On false, string has only numbers.


Y
Yannick Huber

You can use Regex.Match

if(text.matches("\\d*")&& text.length() > 2){
    System.out.println("number");
}

Or you could use onversions like Integer.parseInt(String) or better Long.parseLong(String) for bigger numbers like for example:

private boolean onlyContainsNumbers(String text) {
    try {
        Long.parseLong(text);
        return true;
    } catch (NumberFormatException ex) {
        return false;
    }
} 

And then test with:

if (onlyContainsNumbers(text) && text.length() > 2) {
    // do Stuff
}

.matches("^\\d+$")
J
Jafar Karuthedath

A solution with Java 8 streams and lambda

String data = "12345";
boolean isOnlyNumbers = data.chars().allMatch(Character::isDigit);

p
pseudoramble

There are lots of facilities to obtain numbers from Strings in Java (and vice versa). You may want to skip the regex part to spare yourself the complication of that.

For example, you could try and see what Double.parseDouble(String s) returns for you. It should throw a NumberFormatException if it does not find an appropriate value in the string. I would suggest this technique because you could actually make use of the value represented by the String as a numeric type.


Using an exception as a why to test your input might be a bad idea, exceptions create a big overhead.
@OfirLuzon I agree that exceptions are not a great way to handle expected cases that are going to arise. However I think it's hard to tell if there would be a performance hit without more context.
U
Usman Javaid
import java.util.*;

class Class1 {
    public static void main(String[] argh) {
        boolean ans = CheckNumbers("123");
        if (ans == true) {
            System.out.println("String contains numbers only");
        } else {
            System.out.println("String contains other values as well");

        }
    }


    public static boolean CheckNumbers(String input) {
        for (int ctr = 0; ctr < input.length(); ctr++) {
            if ("1234567890".contains(Character.valueOf(input.charAt(ctr)).toString())) {
                continue;
            } else {
                return false;
            }
        }
        return true;
    }
}

S
Saurabh Gaddelpalliwar

Here is my code, hope this will help you !

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

    if (text.matches("[0-9]+") && text.length() > 2) {
        isDigit = true;
    }else {
        isDigit = false;
    }

    return isDigit;
}

F
F. Müller
StringUtils.isNumeric("1234")

this works fine.


T
Thiago

Here is a sample. Find only the digits in a String and Process formation as needed.

text.replaceAll("\\d(?!$)", "$0 ");

For more info check google Docs https://developer.android.com/reference/java/util/regex/Pattern Where you can use Pattern


R
Ryan Stewart

This code is already written. If you don't mind the (extremely) minor performance hit--which is probably no worse than doing a regex match--use Integer.parseInt() or Double.parseDouble(). That'll tell you right away if a String is only numbers (or is a number, as appropriate). If you need to handle longer strings of numbers, both BigInteger and BigDecimal sport constructors that accept Strings. Any of these will throw a NumberFormatException if you try to pass it a non-number (integral or decimal, based on the one you choose, of course). Alternately, depending on your requirements, just iterate the characters in the String and check Character.isDigit() and/or Character.isLetter().


J
JamisonMan111
Character first_letter_or_number = query.charAt(0);
                //------------------------------------------------------------------------------
                if (Character.isDigit())
                {

                }
                else if (Character.isLetter())
                {

                }

v
vaquar khan

Working test example

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

public class PaserNo {

    public static void main(String args[]) {

        String text = "gg";

        if (!StringUtils.isBlank(text)) {
            if (stringContainsNumber(text)) {
                int no=Integer.parseInt(text.trim());
                System.out.println("inside"+no);

            } else {
                System.out.println("Outside");
            }
        }
        System.out.println("Done");
    }

    public static boolean stringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }
}

Still your code can be break by "1a" etc so you need to check exception

if (!StringUtils.isBlank(studentNbr)) {
                try{
                    if (isStringContainsNumber(studentNbr)){
                    _account.setStudentNbr(Integer.parseInt(studentNbr.trim()));
                }
                }catch(Exception e){
                    e.printStackTrace();
                    logger.info("Exception during parse studentNbr"+e.getMessage());
                }
            }

Method for checking no is string or not

private boolean isStringContainsNumber(String s) {
        Pattern p = Pattern.compile("[0-9]");
        Matcher m = p.matcher(s);
        return m.find();
    }

A
Adam Bodrogi

It is a bad practice to involve any exception throwing/handling into such a typical scenario. Therefore a parseInt() is not nice, but a regex is an elegant solution for this, but take care of the following: -fractions -negative numbers -decimal separator might differ in contries (e.g. ',' or '.') -sometimes it is allowed to have a so called thousand separator, like a space or a comma e.g. 12,324,1000.355

To handle all the necessary cases in your application you have to be careful, but this regex covers the typical scenarios (positive/negative and fractional, separated by a dot): ^[-+]?\d*.?\d+$
For testing, I recommend regexr.com.


u
user176692

Slightly modified version of Adam Bodrogi's:

public class NumericStr {


public static void main(String[] args) {
    System.out.println("Matches: "+NumericStr.isNumeric("20"));         // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("20,00"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("30,000.01"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("-2980"));          // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("$20"));            // Should be true
    System.out.println("Matches: "+NumericStr.isNumeric("jdl"));            // Should be false
    System.out.println("Matches: "+NumericStr.isNumeric("2lk0"));           // Should be false
}

public static boolean isNumeric(String stringVal) {
    if (stringVal.matches("^[\\$]?[-+]?[\\d\\.,]*[\\.,]?\\d+$")) {
        return true;
    }

    return false;
}
}

Had to use this today so just posted my modifications. Includes currency, thousands comma or period notation, and some validations. Does not include other currency notations (euro, cent), verification commas are every third digit.


S
Sandeep
public class Test{  
public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    String str;
    boolean status=false;
    System.out.println("Enter the String : ");
    str = sc.nextLine();
    
    char ch[] = str.toCharArray();
    
    for(int i=0;i<ch.length;i++) {
        if(ch[i]=='1'||ch[i]=='2'||ch[i]=='3'||ch[i]=='4'||ch[i]=='5'||ch[i]=='6'||ch[i]=='7'||ch[i]=='8'||ch[i]=='9'||ch[i]=='0') {
            ch[i] = 0;
        }
    }
    
    for(int i=0;i<ch.length;i++) {
        if(ch[i] != 0) {
            System.out.println("Mixture of letters and Digits");
            status = false;
            break;
        }
        else
            status = true;
    }
    
    if(status == true){
        System.out.println("Only Digits are present");
    }
}

}