Java에서 문자열이 숫자인지 확인하는 방법


886

문자열을 구문 분석하기 전에 숫자인지 어떻게 확인합니까?


36
정기적 인 설명으로 제안 된 모든 솔루션은 16 진수로 작동하지 않습니다.
Oscar Castiblanco 2012

matches (...) 함수에 null 문자열을 전달하면 NullPointer 예외가 발생합니다.
Hitesh Sahu

타사 라이브러리가없는 간결한 Java 8 솔루션에 대해서는 Max Malysh의 답변을 참조하십시오.
Andy Thomas

@HiteshSahu null 문자열은 최신 버전 (Java 6.x 및 7.x 포함)에서 정상적으로 처리되는 것으로 보입니다.
lifebalance

사용하도록 제안 된 모든 솔루션은와 ( Integer.parseInt()과)의 휴대 전화 번호를 구문 분석하지 못합니다 NumberFormatException.
버그가 아닙니다.

답변:


691

아파치 코 몬즈 랭 3.5 이상 : NumberUtils.isCreatableStringUtils.isNumeric.

아파치 코 몬즈 랭 3.4 이하 : NumberUtils.isNumberStringUtils.isNumeric.

빈 문자열에 대한 StringUtils.isNumericSpace반환 값 true을 사용 하고 문자열의 내부 공간을 무시할 수도 있습니다 . 또 다른 방법은 NumberUtils.isParsable기본적으로 Java에 따라 파싱 가능한 수를 확인하는 사용 하는 것입니다. 링크 된 javadoc에는 각 메소드에 대한 자세한 예제가 포함되어 있습니다.


59
StringUtils.isNumeric()문자열이 일련의 숫자인지 확인하기 때문에 여기에 적합하지 않을 것입니다. 대부분의 int에 대한 미세하지만 그렇게 등 소수, 그룹 단락 문자와 숫자가 될 것입니다
제프 메르 카도

42
한 곳에서 3 줄 기능이 필요하기 때문에 전체 라이브러리를 포함하지 않기 때문에 바퀴를 재발 명하십시오.
dalvarezmartinez1

12
그래도이 기능을 위해 전체 라이브러리를 추가 할 가치가 있습니까? 분명히 다른 것들과 함께 사용된다면 사람들이 이것을 한 줄의 코드로 해결했다는 것을 고려하면 과잉입니다.

7
제외와 함께 작동하지 않습니다. 그리고 모든 숫자의 절반이 음수이므로 .....
Paul Draper

6
@PaulDraper : 맞습니다. StringUtils선행 기호는 지원하지 않지만 확인해야 NumberUtils.isCreatable합니다. 음수를 올바르게 지원합니다.
palacsint

904

이것은 일반적으로 간단한 사용자 정의 함수 (예 : Roll-your-own "isNumeric"함수)로 수행됩니다.

다음과 같은 것 :

public static boolean isNumeric(String str) { 
  try {  
    Double.parseDouble(str);  
    return true;
  } catch(NumberFormatException e){  
    return false;  
  }  
}

그러나이 함수를 많이 호출하고 숫자가 아니기 때문에 많은 검사가 실패 할 것으로 예상하면이 메커니즘의 성능은 좋지 않습니다. 각 실패마다 예외가 발생하기 때문입니다. 상당히 비싼 작업입니다.

다른 방법은 정규식을 사용하여 숫자의 유효성을 검사하는 것입니다.

public static boolean isNumeric(String str) {
  return str.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.
}

그러나 아랍어 이외의 숫자 (예 : 0에서 9 이외의 숫자)를 사용하면 위의 RegEx 메커니즘에주의해야합니다. 이는 RegEx의 "\ d"부분이 [0-9]에만 일치하고 효과적으로 국제적으로 숫자를 인식하지 못하기 때문입니다. (OregonGhost에게 이것을 지적 해 주셔서 감사합니다!)

또는 다른 대안은 Java의 내장 java.text.NumberFormat 객체를 사용하여 문자열을 구문 분석 한 후 구문 분석기 위치가 문자열의 끝에 있는지 확인하는 것입니다. 그렇다면 전체 문자열이 숫자라고 가정 할 수 있습니다.

public static boolean isNumeric(String str) {
  NumberFormat formatter = NumberFormat.getInstance();
  ParsePosition pos = new ParsePosition(0);
  formatter.parse(str, pos);
  return str.length() == pos.getIndex();
}

7
Java Regex의 \ d는 라틴 숫자 만 일치합니까? .NET 정규 표현식과 같은 경우 다음 설명에 따라 다른 (예 : 아랍어) 숫자에 문제가 발생할 수 있습니다. blogs.msdn.com/oldnewthing/archive/2004/03/09/86555.aspx
OregonGhost

3
numberFormatter 솔루션은 아마도 NumberFormatException을 잡는 것보다 조금 더 나을 것입니다. 가장 좋은 방법은 정규식을 사용하는 것입니다.
Chii

11
점을 유의 .하여 정규식에 어떤 문자 만이 아니라 소수 구분 문자와 일치합니다.
jqno

9
try / catch의 비용을 실현하기위한 +1 이것은 실제로 반복적으로 사용하기 위해 장기적으로 사용하는 끔찍한 접근법이지만 실제로 우리는 Java에서 그와 붙어 있습니다.
demongolem

5
"라틴 숫자"와 같은 것은 없으며, 숫자 0-9는 사실상 아라비아 숫자이다. 사람들은 아마도 로마 숫자를 가진 가족 일 것입니다. 로마 숫자는 I, II, III, IV, V, VI 등의 라틴어를 사용하는 사람들이 사용했습니다. en.wikipedia.org/wiki/Arabic_numerals ; en.wikipedia.org/wiki/Roman_numerals
dantiston

152

당신이 안드로이드에 있다면, 당신은 사용해야합니다 :

android.text.TextUtils.isDigitsOnly(CharSequence str)

설명서는 여기에서 찾을 수 있습니다

간단하게 유지하십시오 . 대부분의 사람들은 "다시 프로그래밍"할 수 있습니다 (같은 것).


4
@ kape123 :) "123.456"은 숫자를 포함하지 않습니다.
Ahmed Alejo

8
참고 : 이로 인해 널 입력에 대해 NPE가 발생합니다. 또한 음수 또는 소수에는 작동하지 않습니다.
gMale

2
나는 그것을 좋아한다 !! 나는 이것이 절대적으로 숫자라고 생각합니다. 하지에 대한 .,-
illusionJJ

이것은 내가 찾던 것입니다. 숫자 0-9 만 확인하는 간단한 것. EditText 선언에 필터를 설정했지만 도로가 바뀌거나 교체되는 경우 간단한 프로그래밍 방식 검사를 수행하는 것이 좋습니다.
jwehrle 2016 년

127

Java 8 람다 식.

String someString = "123123";
boolean isNumeric = someString.chars().allMatch( Character::isDigit );

4
메소드 참조도 사용할 수 있습니다. someString.chars (). allMatch (Character :: isDigit)
Wienczny

3
멋지지만 여전히 휠을 거의 모든 "솔루션"으로 재창조하고 있습니다. 또한 'null'(거의 다른 모든 것)에서 실패합니다.
qben

8
이 답변은 간결하고 간단하며 읽을 수 있습니다. 거의 영어처럼 읽을 수 있습니다. "chars all match numerics". 타사 라이브러리가 필요하지 않습니다. 예외가 아닌 경우에는 예외를 사용하지 않습니다. 이 답변이 받아 들여 져야합니다.
Andy Thomas

14
"-1"을 위해 무엇을 생산할까요?
Balázs Németh

2
정답이 아닙니다. 숫자 문자열은 숫자가 아닌 문자 (예 : "."또는 "-")를 가질 수 있으며 여전히 완벽하게 숫자입니다. 예를 들어 0.5, -1 및 1,000은 모두이 답변으로 실패하지만 완벽하게 수치입니다.
Simeon G

125

@CraigTP가 그의 탁월한 답변에서 언급했듯이 예외를 사용하여 문자열이 숫자인지 여부를 테스트하는 것과 비슷한 성능 문제가 있습니다. 그래서 문자열을 나누고을 사용 java.lang.Character.isDigit()합니다.

public static boolean isNumeric(String str)
{
    for (char c : str.toCharArray())
    {
        if (!Character.isDigit(c)) return false;
    }
    return true;
}

에 따르면 Javadoc을 , Character.isDigit(char)의지가 제대로 라틴어가 아닌 숫자를 인식합니다. 성능 측면에서, N이 문자열의 문자 수인 간단한 N 수의 비교는 정규식 일치를 수행하는 것보다 계산적으로 효율적이라고 생각합니다.

업데이트 : 의견에서 Jean-François Corbett이 지적한 것처럼 위의 코드는 양의 정수 만 유효성을 검사하므로 대부분의 유스 케이스를 포괄합니다. 다음은 시스템에서 사용되는 기본 로케일에 따라 소수를 올바르게 유효성 검증하는 업데이트 된 코드이며 소수 구분 기호는 문자열에서 한 번만 발생한다는 가정입니다.

public static boolean isStringNumeric( String str )
{
    DecimalFormatSymbols currentLocaleSymbols = DecimalFormatSymbols.getInstance();
    char localeMinusSign = currentLocaleSymbols.getMinusSign();

    if ( !Character.isDigit( str.charAt( 0 ) ) && str.charAt( 0 ) != localeMinusSign ) return false;

    boolean isDecimalSeparatorFound = false;
    char localeDecimalSeparator = currentLocaleSymbols.getDecimalSeparator();

    for ( char c : str.substring( 1 ).toCharArray() )
    {
        if ( !Character.isDigit( c ) )
        {
            if ( c == localeDecimalSeparator && !isDecimalSeparatorFound )
            {
                isDecimalSeparatorFound = true;
                continue;
            }
            return false;
        }
    }
    return true;
}

4
소수점 구분 기호도 실패하지 않습니까?
Jean-François Corbett

1
@ Jean-FrançoisCorbett : 좋은 점, 소수점 구분 기호를 허용하는 최신 코드로 코드를 업데이트했습니다.
이브라힘 아리프

2
-ve 부호가이 기능에 실패합니까?
java_mouse

3
toCharArray()문자열은 변경할 수 없으므로 호출 하면 String 객체에 배열의 복사본이 만들어집니다. 아마도 charAt(int index)String 객체 에서 메소드를 직접 사용하는 것이 더 빠를 것 입니다.
Mike Kucera

2
StringIndexOutOfBoundsException길이가 0 인 문자열을 전달하면 생성 됩니다. 다음과 같이 수정 가능if(str.length() == 0) return false;
samgak

43

Google의 구아바 라이브러리는 다음과 같은 유용한 도우미 방법을 제공합니다 Ints.tryParse. 당신은 같이 사용할 수 Integer.parseInt있지만 반환 null이 아닌 문자열이 유효한 정수로 구문 분석하지 않는 경우 예외를 throw합니다. int가 아닌 Integer를 반환하므로 int로 다시 변환 / 오토 박스해야합니다.

예:

String s1 = "22";
String s2 = "22.2";
Integer oInt1 = Ints.tryParse(s1);
Integer oInt2 = Ints.tryParse(s2);

int i1 = -1;
if (oInt1 != null) {
    i1 = oInt1.intValue();
}
int i2 = -1;
if (oInt2 != null) {
    i2 = oInt2.intValue();
}

System.out.println(i1);  // prints 22
System.out.println(i2);  // prints -1

그러나 현재 릴리스 인 Guava r11에서는 여전히 @Beta로 표시되어 있습니다.

나는 그것을 벤치마킹하지 않았습니다. 소스 코드를 보면 많은 온 전성 검사로 인한 오버 헤드가 있지만 결국 Character.digit(string.charAt(idx))@Ibrahim의 대답과 비슷하지만 약간 다릅니다. 구현시 커버 아래에서 예외 처리 오버 헤드가 없습니다.


인수가 null 인 경우 NPE가 발생한다는 점에 유의하십시오.
Vadzim

30

값을 확인하기 위해 예외를 사용하지 마십시오. 아파치 NumberUtils 대신 Util 라이브러리를 사용하십시오 :

NumberUtils.isNumber(myStringValue);

편집 :

문자열이 0으로 시작하면 NumberUtils는 값을 16 진수로 해석합니다.

NumberUtils.isNumber("07") //true
NumberUtils.isNumber("08") //false

7
3 년 전에 수락 된 답변은 이미 다루었 다 Number.isNumber().
Andy Thomas

나는 그렇게 생각하지 않습니다. 승인되었거나 답변이 변경되었습니다. 수락 된 답변이 NumberUtils에 적용되지 않았기 때문에 답변을 추가 한 이유를 기억합니다. 그러나 의견에 감사드립니다
Goot

2
@Goot-수락 된 답변의 역사는 Number.isNumber()9 월 24 일 12시 17 분 1 초의 답변 의 첫 번째 버전에서 나온 것을 보여줍니다 .
Andy Thomas

@ Goot, StringUtils와 달리 십진수 값 검사를 다루기 때문에 꽤 좋습니다.
Heena Hussain

24

왜 모두가 예외 / 정규 솔루션을 추진하고 있습니까?

try / catch를 사용하면 대부분의 사람들이 훌륭하다는 것을 알 수 있지만 자주하고 싶다면 너무 과세 될 수 있습니다.

내가 여기서 한 일은 정규식, parseNumber () 메소드 및 배열 검색 메소드를 사용하여 가장 효율적인 것을 확인하는 것입니다. 이번에는 정수만 보았습니다.

public static boolean isNumericRegex(String str) {
    if (str == null)
        return false;
    return str.matches("-?\\d+");
}

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    char[] data = str.toCharArray();
    if (data.length <= 0)
        return false;
    int index = 0;
    if (data[0] == '-' && data.length > 1)
        index = 1;
    for (; index < data.length; index++) {
        if (data[index] < '0' || data[index] > '9') // Character.isDigit() can go here too.
            return false;
    }
    return true;
}

public static boolean isNumericException(String str) {
    if (str == null)
        return false;
    try {  
        /* int i = */ Integer.parseInt(str);
    } catch (NumberFormatException nfe) {  
        return false;  
    }
    return true;
}

내가 얻은 속도의 결과는 다음과 같습니다.

Done with: for (int i = 0; i < 10000000; i++)...

With only valid numbers ("59815833" and "-59815833"):
    Array numeric took 395.808192 ms [39.5808192 ns each]
    Regex took 2609.262595 ms [260.9262595 ns each]
    Exception numeric took 428.050207 ms [42.8050207 ns each]
    // Negative sign
    Array numeric took 355.788273 ms [35.5788273 ns each]
    Regex took 2746.278466 ms [274.6278466 ns each]
    Exception numeric took 518.989902 ms [51.8989902 ns each]
    // Single value ("1")
    Array numeric took 317.861267 ms [31.7861267 ns each]
    Regex took 2505.313201 ms [250.5313201 ns each]
    Exception numeric took 239.956955 ms [23.9956955 ns each]
    // With Character.isDigit()
    Array numeric took 400.734616 ms [40.0734616 ns each]
    Regex took 2663.052417 ms [266.3052417 ns each]
    Exception numeric took 401.235906 ms [40.1235906 ns each]

With invalid characters ("5981a5833" and "a"):
    Array numeric took 343.205793 ms [34.3205793 ns each]
    Regex took 2608.739933 ms [260.8739933 ns each]
    Exception numeric took 7317.201775 ms [731.7201775 ns each]
    // With a single character ("a")
    Array numeric took 291.695519 ms [29.1695519 ns each]
    Regex took 2287.25378 ms [228.725378 ns each]
    Exception numeric took 7095.969481 ms [709.5969481 ns each]

With null:
    Array numeric took 214.663834 ms [21.4663834 ns each]
    Regex took 201.395992 ms [20.1395992 ns each]
    Exception numeric took 233.049327 ms [23.3049327 ns each]
    Exception numeric took 6603.669427 ms [660.3669427 ns each] if there is no if/null check

면책 조항 :이 방법이 100 % 최적화되었다고 주장하지는 않으며 단지 데이터를 보여주기위한 것입니다.

숫자가 4 자 이하이고 모든 문자열이 항상 숫자 인 경우에만 예외가 발생합니다.이 경우 왜 검사를해야합니까?

즉, try / catch를 사용하여 유효하지 않은 숫자를 자주 사용하면 매우 고통 스럽습니다. 내가 항상 따르는 중요한 규칙 은 프로그램 흐름에 try / catch를 사용하지 않는 것 입니다. 이것이 왜 예입니다.

흥미롭게도 간단한 경우 char <0 || > 9는 작성이 매우 간단하고 기억하기 쉬우 며 (다국어로 작동해야 함) 거의 모든 테스트 시나리오에서 승리했습니다.

유일한 단점은 Integer.parseInt ()가 ASCII가 아닌 숫자를 처리 할 수 ​​있다고 생각하지만 배열 검색 방법은 그렇지 않습니다.


내가 왜 문자 배열 1을 기억하는 것이 쉬운 지 궁금해하는 사람들을 위해, 음수 부호가 없다는 것을 알고 있다면 다음과 같이 요약 된 것을 쉽게 벗어날 수 있습니다.

public static boolean isNumericArray(String str) {
    if (str == null)
        return false;
    for (char c : str.toCharArray())
        if (c < '0' || c > '9')
            return false;
    return true;

마지막으로 마지막으로, 나는 모든 투표권을 가진 수락 된 예제에서 어설 션 연산자에 대해 궁금했습니다. 할당에 추가

double d = Double.parseDouble(...)

값을 사용하지 않기 때문에 쓸모가 없을뿐만 아니라 처리 시간을 낭비하고 런타임을 몇 나노초까지 늘 렸습니다 (테스트에서 100-200ms 증가). 실제로 성능을 낮추기위한 추가 작업이므로 다른 사람이 왜 그렇게하는지 알 수 없습니다.

당신은 그것이 최적화 될 것이라고 생각할 것입니다 ...하지만 아마도 바이트 코드를 확인하고 컴파일러가 무엇을하고 있는지 확인해야합니다. 그것은 어떻게 든 최적화되어 있지만 항상 나에게 더 길어진 이유를 설명하지는 않습니다 ... 그래서 나는 무슨 일이 일어나고 있는지 궁금합니다. 참고로 더 길어지면 10000000 반복 테스트를 실행하고 해당 프로그램을 여러 번 실행하면 (10x +) 항상 느려진 것으로 나타났습니다.

편집 : Character.isDigit ()에 대한 테스트가 업데이트되었습니다.


4
매번 새로운 정규 표현식을 컴파일하지 않습니까? 그다지 효율적이지 않습니다.
사무엘 에드윈 워드

1
@SamuelEdwinWard 그게 내가이 포스트를 만든 모든 이유는 ... 정규식 예제는 다른 사람들이 제공 한 답변을 사용했고 그것이 얼마나 비효율적인지를 보여주었습니다. 미리 컴파일하여 정규 표현식으로 시도하고 그만 사용하더라도 시간 차이는 다음과 같습니다. 다른 제공된 사람들이 게시 한 정규 표현식의 경우 2587ms, 미리 컴파일 할 때 950ms, 미리 컴파일 할 때 144ms 숫자 형 배열 (동일한 문자열의 1mil 반복). 미리 컴파일하면 분명히 도움이되지만 슬프게도 배열 방식보다 훨씬 열등합니다 ... 알지 못하는 미친 최적화가 없다면.

Regex가 일을 더 빠르게 만든다고 믿는 것은 거의 잘못된 것입니다. 그것의 일회성 검색이라면, 그렇습니다. 그러나 효율적으로 작성된 코드가 실제로 정규 표현식보다 뛰어나다는 사실을 알았습니다. Great Post @Water
Yo Apps

19
public static boolean isNumeric(String str)
{
    return str.matches("-?\\d+(.\\d+)?");
}

CraigTP의 정규 표현식 (위에 표시됨)은 약간의 오탐 (false positive)을 생성합니다. 예를 들어, "23y4"는 '.'때문에 숫자로 계산됩니다. 소수점이 아닌 모든 문자와 일치합니다.

또한 선행 '+'가있는 숫자는 거부합니다.

이 두 가지 사소한 문제를 피하는 대안은

public static boolean isNumeric(String str)
{
    return str.matches("[+-]?\\d*(\\.\\d+)?");
}

이 반환됩니다 true하나의 플러스 "+"또는 마이너스 "-", 그리고 false위한"0."
user85421

단일 플러스 또는 마이너스를 잘 잡습니다. "0"입니다. 유효한 숫자?
user872985

"0."유효 Double.parseDouble()및 JLS (따른 유효 리터럴 §3.10.2 )!
user85421

정규 표현식을 만드는 것도 비용이 많이 듭니다. 정규 표현식은 한 번 생성하고 재사용 할 수 있어야합니다
다니엘 Nuriyev

1
로 변경해야합니다matches("-?\\d+([.]\\d+)?")
Bobs

14

주어진 문자열의 모든 숫자를 빈 공간 ( "")으로 바꾸려고 시도 할 수 있습니다. 즉, 빈 공간이 0 인 경우 주어진 문자열에 숫자 만 포함되어 있다고 말할 수 있습니다. [이 답변이 도움이 되었으면 투표를 고려하십시오] 예 :

boolean isNumber(String str){
        if(str.length() == 0)
            return false; //To check if string is empty

        if(str.charAt(0) == '-')
            str = str.replaceFirst("-","");// for handling -ve numbers

        System.out.println(str);

        str = str.replaceFirst("\\.",""); //to check if it contains more than one decimal points

        if(str.length() == 0)
            return false; // to check if it is empty string after removing -ve sign and decimal point
        System.out.println(str);

        return str.replaceAll("[0-9]","").length() == 0;
    }

그래서 ""숫자에 불과하다 "3.14"하고 "-1"있지?
Eric Duminil

분명히 모든 숫자 형태에 적용되는 것은 아니지만, 다르게 생각할 수있는 공감대가 있습니다.
gbenroscience

12

당신은 사용할 수 있습니다 NumberFormat#parse:

try
{
     NumberFormat.getInstance().parse(value);
}
catch(ParseException e)
{
    // Not a number.
}

편집을 제공했습니다-.getInstance ()가 없습니다. 이 질문을 찾을 때 함께 한 답이 +1입니다.
8bitjunkie

5
비용이 많이 드는 경우 확장 가능 사용
다니엘 Nuriyev

1
끝에 가비지 문자가있는 경우에도 전달됩니다 value.
브라이언 화이트

예외를 기록하지 않으면 소나 문제가 발생합니다.
jmhostalet

1
Double.parseDouble이 작동하지 않는 숫자 형식 0x0001에서 작동했습니다. +1
Seabass77. 18. 16. 18.


8

여기에 문제에 대한 대답이 있습니다.

모든 유형의 구문 분석기로 문자열을 구문 분석하는 데 사용할 수있는 모든 편리한 메소드를 포착하십시오 isParsable(Object parser, String str). 파서는 a Class또는 a 일 수 있습니다 object. 또한 작성한 사용자 정의 파서를 사용할 수 있으며 다음과 같은 시나리오에서 작동해야합니다.

isParsable(Integer.class, "11");
isParsable(Double.class, "11.11");
Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");

다음은 메소드 설명이 포함 된 코드입니다.

import java.lang.reflect.*;

/**
 * METHOD: isParsable<p><p>
 * 
 * This method will look through the methods of the specified <code>from</code> parameter
 * looking for a public method name starting with "parse" which has only one String
 * parameter.<p>
 * 
 * The <code>parser</code> parameter can be a class or an instantiated object, eg:
 * <code>Integer.class</code> or <code>new Integer(1)</code>. If you use a
 * <code>Class</code> type then only static methods are considered.<p>
 * 
 * When looping through potential methods, it first looks at the <code>Class</code> associated
 * with the <code>parser</code> parameter, then looks through the methods of the parent's class
 * followed by subsequent ancestors, using the first method that matches the criteria specified
 * above.<p>
 * 
 * This method will hide any normal parse exceptions, but throws any exceptions due to
 * programmatic errors, eg: NullPointerExceptions, etc. If you specify a <code>parser</code>
 * parameter which has no matching parse methods, a NoSuchMethodException will be thrown
 * embedded within a RuntimeException.<p><p>
 * 
 * Example:<br>
 * <code>isParsable(Boolean.class, "true");<br>
 * isParsable(Integer.class, "11");<br>
 * isParsable(Double.class, "11.11");<br>
 * Object dateFormater = new java.text.SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");<br>
 * isParsable(dateFormater, "2001.07.04 AD at 12:08:56 PDT");<br></code>
 * <p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @throws java.lang.NoSuchMethodException If no such method is accessible 
 */
public static boolean isParsable(Object parser, String str) {
    Class theClass = (parser instanceof Class? (Class)parser: parser.getClass());
    boolean staticOnly = (parser == theClass), foundAtLeastOne = false;
    Method[] methods = theClass.getMethods();

    // Loop over methods
    for (int index = 0; index < methods.length; index++) {
        Method method = methods[index];

        // If method starts with parse, is public and has one String parameter.
        // If the parser parameter was a Class, then also ensure the method is static. 
        if(method.getName().startsWith("parse") &&
            (!staticOnly || Modifier.isStatic(method.getModifiers())) &&
            Modifier.isPublic(method.getModifiers()) &&
            method.getGenericParameterTypes().length == 1 &&
            method.getGenericParameterTypes()[0] == String.class)
        {
            try {
                foundAtLeastOne = true;
                method.invoke(parser, str);
                return true; // Successfully parsed without exception
            } catch (Exception exception) {
                // If invoke problem, try a different method
                /*if(!(exception instanceof IllegalArgumentException) &&
                   !(exception instanceof IllegalAccessException) &&
                   !(exception instanceof InvocationTargetException))
                        continue; // Look for other parse methods*/

                // Parse method refuses to parse, look for another different method
                continue; // Look for other parse methods
            }
        }
    }

    // No more accessible parse method could be found.
    if(foundAtLeastOne) return false;
    else throw new RuntimeException(new NoSuchMethodException());
}


/**
 * METHOD: willParse<p><p>
 * 
 * A convienence method which calls the isParseable method, but does not throw any exceptions
 * which could be thrown through programatic errors.<p>
 * 
 * Use of {@link #isParseable(Object, String) isParseable} is recommended for use so programatic
 * errors can be caught in development, unless the value of the <code>parser</code> parameter is
 * unpredictable, or normal programtic exceptions should be ignored.<p>
 * 
 * See {@link #isParseable(Object, String) isParseable} for full description of method
 * usability.<p>
 * 
 * @param parser    The Class type or instantiated Object to find a parse method in.
 * @param str   The String you want to parse
 * 
 * @return true if a parse method was found and completed without exception
 * @see #isParseable(Object, String) for full description of method usability 
 */
public static boolean willParse(Object parser, String str) {
    try {
        return isParsable(parser, str);
    } catch(Throwable exception) {
        return false;
    }
}

5

ASCII 숫자 만 포함하는 양의 10 진 정수만 일치 시키려면 다음을 사용하십시오.

public static boolean isNumeric(String maybeNumeric) {
    return maybeNumeric != null && maybeNumeric.matches("[0-9]+");
}

5

try-catch를 피하고 음수 및 과학적 표기법을 처리하는 우수한 성능의 접근 방식입니다.

Pattern PATTERN = Pattern.compile( "^(-?0|-?[1-9]\\d*)(\\.\\d+)?(E\\d+)?$" );

public static boolean isNumeric( String value ) 
{
    return value != null && PATTERN.matcher( value ).matches();
}

5

다음은 문자열이 숫자인지 확인하는 클래스입니다. 또한 숫자 문자열을 수정합니다.

풍모:

  1. 불필요한 0을 제거합니다. [ "12.0000000"-> "12"]
  2. 불필요한 0을 제거합니다. [ "12.0580000"-> "12.058"]
  3. 숫자가 아닌 문자를 제거합니다. [ "12.00sdfsdf00"-> "12"]
  4. 음수 문자열 값을 처리합니다. [ "-12,020000"-> "-12.02"]
  5. 여러 점을 제거합니다. [ "-12.0.20.000"-> "-12.02"]
  6. 추가 라이브러리가 없으며 표준 Java 만

여기 있습니다 ...

public class NumUtils {
    /**
     * Transforms a string to an integer. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToInteger(String str) {
        String s = str;
        double d;
        d = Double.parseDouble(makeToDouble(s));
        int i = (int) (d + 0.5D);
        String retStr = String.valueOf(i);
        System.out.printf(retStr + "   ");
        return retStr;
    }

    /**
     * Transforms a string to an double. If no numerical chars returns a String "0".
     *
     * @param str
     * @return retStr
     */
    static String makeToDouble(String str) {

        Boolean dotWasFound = false;
        String orgStr = str;
        String retStr;
        int firstDotPos = 0;
        Boolean negative = false;

        //check if str is null
        if(str.length()==0){
            str="0";
        }

        //check if first sign is "-"
        if (str.charAt(0) == '-') {
            negative = true;
        }

        //check if str containg any number or else set the string to '0'
        if (!str.matches(".*\\d+.*")) {
            str = "0";
        }

        //Replace ',' with '.'  (for some european users who use the ',' as decimal separator)
        str = str.replaceAll(",", ".");
        str = str.replaceAll("[^\\d.]", "");

        //Removes the any second dots
        for (int i_char = 0; i_char < str.length(); i_char++) {
            if (str.charAt(i_char) == '.') {
                dotWasFound = true;
                firstDotPos = i_char;
                break;
            }
        }
        if (dotWasFound) {
            String befDot = str.substring(0, firstDotPos + 1);
            String aftDot = str.substring(firstDotPos + 1, str.length());
            aftDot = aftDot.replaceAll("\\.", "");
            str = befDot + aftDot;
        }

        //Removes zeros from the begining
        double uglyMethod = Double.parseDouble(str);
        str = String.valueOf(uglyMethod);

        //Removes the .0
        str = str.replaceAll("([0-9])\\.0+([^0-9]|$)", "$1$2");

        retStr = str;

        if (negative) {
            retStr = "-"+retStr;
        }

        return retStr;

    }

    static boolean isNumeric(String str) {
        try {
            double d = Double.parseDouble(str);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

}

5

정규식 일치

다음은 더 많은 검증과 일치하는 업그레이드 된 "CraigTP"정규식의 또 다른 예입니다.

public static boolean isNumeric(String str)
{
    return str.matches("^(?:(?:\\-{1})?\\d+(?:\\.{1}\\d+)?)$");
}
  1. 하나의 음수 부호 만 -허용되며 시작 부분에 있어야합니다.
  2. 음수 부호 뒤에 숫자가 있어야합니다.
  3. 소수점 하나만 .허용됩니다.
  4. 소수점 뒤에 숫자가 있어야합니다.

정규식 테스트

1                  --                   **VALID**
1.                 --                   INVALID
1..                --                   INVALID
1.1                --                   **VALID**
1.1.1              --                   INVALID

-1                 --                   **VALID**
--1                --                   INVALID
-1.                --                   INVALID
-1.1               --                   **VALID**
-1.1.1             --                   INVALID

5

예외는 비싸지 만이 경우 RegEx는 훨씬 오래 걸립니다. 아래 코드는 예외를 사용하는 것과 정규식을 사용하는 두 가지 함수에 대한 간단한 테스트를 보여줍니다. 내 컴퓨터에서 RegEx 버전이 예외보다 10 배 느립니다.

import java.util.Date;


public class IsNumeric {

public static boolean isNumericOne(String s) {
    return s.matches("-?\\d+(\\.\\d+)?");  //match a number with optional '-' and decimal.      
}

public static boolean isNumericTwo(String s) {
    try {
        Double.parseDouble(s);
        return true;
    } catch (Exception e) {
        return false;
    }
}

public static void main(String [] args) {

    String test = "12345.F";

    long before = new Date().getTime();     
    for(int x=0;x<1000000;++x) {
        //isNumericTwo(test);
        isNumericOne(test);
    }
    long after = new Date().getTime();

    System.out.println(after-before);

}

}

일반적으로 이런 종류의 코드는 입력 유형과 같은 것을 확인하는 데 사용됩니다. 이 경우 속도는 고려 사항이 아니며 숫자 또는 숫자가 아닌 수를 확인하기 위해 예외를 던지는 것처럼 잘못된 것을 수행합니다.
user872985

아마. 입력 된 입력은 일반적으로 값을 제출하기 전에 오류가 즉시 표시 될 수있는 UI 구성 요소에 의해 확인됩니다. 성능이 중요한 큰 입력 텍스트 파일에서 문자열의 유효성을 검사하는 것이 더 일반적 일 수 있습니다. 내 대답의 목표는 허용 된 답변의 "예외가 느리다"고 진술하는 것입니다. 복잡한 정규 표현식은 훨씬 비쌉니다. 그리고 내 코드에는 전혀 추한 행동이 없습니다. 위반을 감지하는 가장 빠른 방법입니다. 체크-퍼스트-그런-계산 방법을 사용하면 입력을 통해 두 단계를 수행합니다. 하나는 확인하고 다른 하나는 변환합니다.
ChrisCantrell

5

// 아래 코드를 확인하십시오

public static boolean isDigitsOnly(CharSequence str) {
    final int len = str.length();
    for (int i = 0; i < len; i++) {
        if (!Character.isDigit(str.charAt(i))) {
            return false;
        }
    }
    return true;
}

질문은 정수가 아닌 값을 포함 할 수있는 "숫자"라고합니다.
rghome

3
// only int
public static boolean isNumber(int num) 
{
    return (num >= 48 && c <= 57); // 0 - 9
}

// is type of number including . - e E 
public static boolean isNumber(String s) 
{
    boolean isNumber = true;
    for(int i = 0; i < s.length() && isNumber; i++) 
    {
        char c = s.charAt(i);
        isNumber = isNumber & (
            (c >= '0' && c <= '9') || (c == '.') || (c == 'e') || (c == 'E') || (c == '')
        );
    }
    return isInteger;
}

// is type of number 
public static boolean isInteger(String s) 
{
    boolean isInteger = true;
    for(int i = 0; i < s.length() && isInteger; i++) 
    {
        char c = s.charAt(i);
        isInteger = isInteger & ((c >= '0' && c <= '9'));
    }
    return isInteger;
}

public static boolean isNumeric(String s) 
{
    try
    {
        Double.parseDouble(s);
        return true;
    }
    catch (Exception e) 
    {
        return false;
    }
}

3

이것은이 검사에 대한 간단한 예입니다.

public static boolean isNumericString(String input) {
    boolean result = false;

    if(input != null && input.length() > 0) {
        char[] charArray = input.toCharArray();

        for(char c : charArray) {
            if(c >= '0' && c <= '9') {
                // it is a digit
                result = true;
            } else {
                result = false;
                break;
            }
        }
    }

    return result;
}

3

java.util.Scanner 오브젝트를 사용할 수 있습니다.

public static boolean isNumeric(String inputData) {
      Scanner sc = new Scanner(inputData);
      return sc.hasNextInt();
    }

2

과학 표기법과 점과 쉼표를 소수점 구분 기호로 허용하도록 CraigTP의 솔루션을 수정했습니다.

^-?\d+([,\.]\d+)?([eE]-?\d+)?$

var re = new RegExp("^-?\d+([,\.]\d+)?([eE]-?\d+)?$");
re.test("-6546"); // true
re.test("-6546355e-4456"); // true
re.test("-6546.355e-4456"); // true, though debatable
re.test("-6546.35.5e-4456"); // false
re.test("-6546.35.5e-4456.6"); // false

2

.NET의 Try * 접근 방식이 마음에 드는 이유입니다. Java와 유사한 전통적인 Parse 메소드 외에도 TryParse 메소드도 있습니다. Java 구문 (매개 변수가 아님)이 좋지 않으므로 다음을 일종의 의사 코드로 취급하십시오. 그래도 개념을 분명히해야합니다.

boolean parseInteger(String s, out int number)
{
    try {
        number = Integer.parseInt(myString);
        return true;
    } catch(NumberFormatException e) {
        return false;
    }
}

용법:

int num;
if (parseInteger("23", out num)) {
    // Do something with num.
}

예, Java에는 "out parameters"가 없으며 Integer 래퍼는 변경할 수 없으므로 (출력을 저장하는 데 유효한 참조로 사용할 수 없으므로) 현명한 관용적 옵션은 구문 분석시 null 일 수있는 Integer 객체를 반환하는 것입니다. 실패한. 더 못생긴 옵션은 int [1]을 출력 매개 변수로 전달하는 것입니다.
포트란

예, Java에 출력 매개 변수가없는 이유에 대한 토론을 기억합니다. 그러나 Integer를 반환하면 (필요한 경우 null로) 괜찮을 것입니다. 권투 / unboxing과 관련하여 Java의 성능에 대해서는 알지 못합니다.
OregonGhost

4
나는 C #을 다음 사람만큼 좋아하지만 Java에 기능이 존재하지 않을 때 Java 질문에 .NET C # 코드 스 니펫을 추가하는 것은
Shane

예외를 기록하지 않으면 소나 문제가 발생합니다.
jmhostalet

2

구문 분석하고 (예 :로 Integer#parseInt) 예외를 포착하십시오. =)

명확히하기 위해 : parseInt 함수는 어떤 경우에도 숫자를 구문 분석 할 수 있는지 확인하고 (어쩌면) 구문 분석하려는 경우 실제로 구문 분석을 수행하여 성능 저하를 일으키지 않습니다.

당신이 그것을 파싱하고 싶지 않거나 (매우 드물게 파싱하고 싶다면) 물론 다르게 할 수도 있습니다.


1
비용이 많이 드는 경우 확장 가능 사용
다니엘 Nuriyev

예외를 기록하지 않으면 소나 문제가 발생합니다.
jmhostalet

사용해 Double.parseDouble
Alex78191

2

Apache Commons Lang의 NumberUtils.isCreatable ()을 사용할 수 있습니다 .

NumberUtils.isNumber는 4.0에서 더 이상 사용되지 않으므로 NumberUtils.isCreatable ()을 대신 사용하십시오.


2

Java 8 스트림, 람다 식, 기능 인터페이스

모든 경우 처리 ( string null, string empty 등 )

String someString = null; // something="", something="123abc", something="123123"

boolean isNumeric = Stream.of(someString)
            .filter(s -> s != null && !s.isEmpty())
            .filter(Pattern.compile("\\D").asPredicate().negate())
            .mapToLong(Long::valueOf)
            .boxed()
            .findAny()
            .isPresent();

2

API를 사용하지 않고 숫자와 소수를 확인하는 조건을 설명했습니다.

수정 길이 1 자리 숫자 확인

Character.isDigit(char)

수정 길이 확인 (길이가 6이라고 가정)

String number = "132452";
if(number.matches("([0-9]{6})"))
System.out.println("6 digits number identified");

(4 ~ 6 길이 가정) 사이의 가변 길이 번호 확인

//  {n,m}  n <= length <= m
String number = "132452";
if(number.matches("([0-9]{4,6})"))
System.out.println("Number Identified between 4 to 6 length");

String number = "132";
if(!number.matches("([0-9]{4,6})"))
System.out.println("Number not in length range or different format");

(4 ~ 7 길이 가정) 사이의 가변 길이 10 진수 확인

//  It will not count the '.' (Period) in length
String decimal = "132.45";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1.12";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "1234";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "-10.123";
if(decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Numbers Identified between 4 to 7");

String decimal = "123..4";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "132";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

String decimal = "1.1";
if(!decimal.matches("(-?[0-9]+(\.)?[0-9]*){4,6}"))
System.out.println("Decimal not in range or different format");

그것이 많은 사람들을 도울 수 있기를 바랍니다.


2

다른 답변을 기반으로 직접 작성했으며 예외 검사와 함께 패턴이나 구문 분석을 사용하지 않습니다.

최대 1 개의 빼기 부호를 확인하고 최대 1 개의 소수점을 검사합니다.

몇 가지 예와 결과는 다음과 같습니다.

"1", "-1", "-1.5"및 "-1.556"이 true를 반환

"1..5", "1A.5", "1.5D", "-"및 "--1"은 false를 반환합니다.

참고 : 필요한 경우 Locale 매개 변수를 승인하고이를 DecimalFormatSymbols.getInstance () 호출로 전달하여 현재 로케일 대신 특정 로케일을 사용할 수 있습니다.

 public static boolean isNumeric(final String input) {
    //Check for null or blank string
    if(input == null || input.isBlank()) return false;

    //Retrieve the minus sign and decimal separator characters from the current Locale
    final var localeMinusSign = DecimalFormatSymbols.getInstance().getMinusSign();
    final var localeDecimalSeparator = DecimalFormatSymbols.getInstance().getDecimalSeparator();

    //Check if first character is a minus sign
    final var isNegative = input.charAt(0) == localeMinusSign;
    //Check if string is not just a minus sign
    if (isNegative && input.length() == 1) return false;

    var isDecimalSeparatorFound = false;

    //If the string has a minus sign ignore the first character
    final var startCharIndex = isNegative ? 1 : 0;

    //Check if each character is a number or a decimal separator
    //and make sure string only has a maximum of one decimal separator
    for (var i = startCharIndex; i < input.length(); i++) {
        if(!Character.isDigit(input.charAt(i))) {
            if(input.charAt(i) == localeDecimalSeparator && !isDecimalSeparatorFound) {
                isDecimalSeparatorFound = true;
            } else return false;
        }
    }
    return true;
}

1

작동 할 수있는 두 가지 방법이 있습니다. (예외를 사용하지 않고). 참고 : Java는 기본적으로 값으로 전달되며 문자열 값은 문자열 객체 데이터의 주소입니다. 그래서, 당신이 할 때

stringNumber = stringNumber.replaceAll(" ", "");

공백이 없도록 입력 값을 변경했습니다. 원하는 경우 해당 줄을 제거 할 수 있습니다.

private boolean isValidStringNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if(!Character.isDigit(charNumber[i]))
        {
            return false;
        }
    }
    return true;
}

여기에 부동 소수점을 허용하려는 경우 다른 방법이 있습니다.이 방법은 양식의 숫자가 1,123,123,123,123,123.123을 통과하도록 허용합니다. 방금 만들었고 작동하는지 확인하기 위해 추가 테스트가 필요하다고 생각합니다.

private boolean isValidStringTrueNumber(String stringNumber)
{
    if(stringNumber.isEmpty())
    {
        return false;
    }

    stringNumber = stringNumber.replaceAll(" ", "");
    int countOfDecimalPoint = 0;
    boolean decimalPointPassed = false;
    boolean commaFound = false;
    int countOfDigitsBeforeDecimalPoint = 0;
    int countOfDigitsAfterDecimalPoint =0 ;
    int commaCounter=0;
    int countOfDigitsBeforeFirstComma = 0;

    char [] charNumber = stringNumber.toCharArray();
    for(int i =0 ; i<charNumber.length ;i++)
    {
        if((commaCounter>3)||(commaCounter<0))
        {
            return false;
        }
        if(!Character.isDigit(charNumber[i]))//Char is not a digit.
        {
            if(charNumber[i]==',')
            {
                if(decimalPointPassed)
                {
                    return false;
                }
                commaFound = true;
                //check that next three chars are only digits.
                commaCounter +=3;
            }
            else if(charNumber[i]=='.')
            {
                decimalPointPassed = true;
                countOfDecimalPoint++;
            }
            else
            {
                return false;
            }
        }
        else //Char is a digit.
        {
            if ((commaCounter>=0)&&(commaFound))
            {
                if(!decimalPointPassed)
                {
                    commaCounter--;
                }
            }

            if(!commaFound)
            {
                countOfDigitsBeforeFirstComma++;
            }

            if(!decimalPointPassed)
            {
                countOfDigitsBeforeDecimalPoint++;
            }
            else
            {
                countOfDigitsAfterDecimalPoint++;
            }
        }
    }
    if((commaFound)&&(countOfDigitsBeforeFirstComma>3))
    {
        return false;
    }
    if(countOfDecimalPoint>1)
    {
        return false;
    }

    if((decimalPointPassed)&&((countOfDigitsBeforeDecimalPoint==0)||(countOfDigitsAfterDecimalPoint==0)))
    {
        return false;
    }
    return true;
}

오, 좋은 질문입니다. 나는 이것이 정상적인 유형의 정수 만 작동한다고 생각합니다. 이 방법은 처음에 입력 전화 번호를 필터링하고 번호를 계산하기 위해 만들어졌습니다.
XForCE07
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.