Java에서 문자열이 숫자인지 확인

1. 소개

종종 String에서 작업하는 동안 String 이 유효한 숫자 인지 아닌지 알아 내야합니다 .

이 튜토리얼에서는 주어진 String 이 numeric 인지 감지하는 여러 방법을 탐색합니다 . 먼저 일반 Java를 사용한 다음 정규 표현식을 사용한 다음 마지막으로 외부 라이브러리를 사용합니다.

다양한 구현에 대한 논의를 마치면 벤치 마크를 사용하여 어떤 방법이 최적인지 파악할 것입니다.

2. 전제 조건

주요 콘텐츠로 이동하기 전에 몇 가지 전제 조건부터 시작하겠습니다.

이 기사의 후반부에서는 pom.xml에 종속성을 추가 할 Apache Commons 외부 라이브러리를 사용합니다 .

 org.apache.commons commons-lang3 3.9 

이 라이브러리의 최신 버전은 Maven Central에서 찾을 수 있습니다.

3. 일반 자바 사용

문자열 이 숫자 인지 아닌지 확인하는 가장 쉽고 안정적인 방법 은 Java의 내장 메소드를 사용하여 구문 분석하는 것입니다.

  1. Integer.parseInt (문자열)
  2. Float.parseFloat (문자열)
  3. Double.parseDouble (문자열)
  4. Long.parseLong (문자열)
  5. new BigInteger (문자열)

이러한 메서드가 NumberFormatException을 throw하지 않으면 구문 분석이 성공했고 문자열 이 숫자 임을 의미합니다 .

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

이 메서드가 실제로 작동하는지 살펴 보겠습니다.

assertThat(isNumeric("22")).isTrue(); assertThat(isNumeric("5.05")).isTrue(); assertThat(isNumeric("-200")).isTrue(); assertThat(isNumeric("10.0d")).isTrue(); assertThat(isNumeric(" 22 ")).isTrue(); assertThat(isNumeric(null)).isFalse(); assertThat(isNumeric("")).isFalse(); assertThat(isNumeric("abc")).isFalse();

우리에 ISNUMERIC () 방법, 우리는 단지 유형입니다 값을 확인하고 두 번 ,하지만이 방법은 또한 확인하기 위해 수정할 수 있습니다 정수 , 플로트 , 우리가 이전에 입대 한 것으로 해석 방법을 사용하여 큰 숫자 .

이러한 메서드는 Java String Conversions 문서에서도 설명합니다.

4. 정규식 사용

이제 regex를 사용합시다 -? \ d + (\. \ d +)? 양수 또는 음수 및 부동 수로 구성된 숫자 문자열 과 일치 합니다.

그러나 이것은 말할 필요도없이이 정규식을 확실히 수정하여 광범위한 규칙을 식별하고 처리 할 수 ​​있습니다. 여기서는 간단하게 유지하겠습니다.

이 정규식을 분석하고 작동 방식을 살펴 보겠습니다.

  • -? –이 부분은 주어진 숫자가 음수인지 식별하고 대시“ ”는 문자 그대로 대시를 검색하며 물음표“ ? ”는 그 존재를 선택 사항으로 표시합니다.
  • \ d + – 하나 이상의 숫자를 검색합니다.
  • (\. \ d +)? – 정규식의이 부분은 부동 숫자를 식별하는 것입니다. 여기서 우리는 마침표가 뒤에 오는 하나 이상의 숫자를 검색합니다. 결국 물음표는이 완전한 그룹이 선택 사항임을 나타냅니다.

정규 표현식은 매우 광범위한 주제입니다. 간략한 개요를 보려면 Java 정규식 API에 대한 자습서를 확인하십시오.

지금은 위의 정규 표현식을 사용하여 메서드를 만들어 보겠습니다.

private Pattern pattern = Pattern.compile("-?\\d+(\\.\\d+)?"); public boolean isNumeric(String strNum) { if (strNum == null) { return false; } return pattern.matcher(strNum).matches(); }

이제 위의 방법에 대한 몇 가지 주장을 살펴 보겠습니다.

assertThat(isNumeric("22")).isTrue(); assertThat(isNumeric("5.05")).isTrue(); assertThat(isNumeric("-200")).isTrue(); assertThat(isNumeric(null)).isFalse(); assertThat(isNumeric("abc")).isFalse();

5. Apache Commons 사용

이 섹션에서는 Apache Commons 라이브러리에서 사용할 수있는 다양한 방법에 대해 설명합니다.

5.1. NumberUtils.isCreatable (문자열)

NumberUtils 아파치 공용 정적 방법을 제공 NumberUtils.isCreatable (문자열) 여부를 확인 문자열이 유효한 자바 번호 여부입니다.

이 방법은 다음을 허용합니다.

  1. 0x 또는 0X로 시작하는 16 진수
  2. 0으로 시작하는 8 진수
  3. 과학적 표기법 (예 : 1.05e-10)
  4. 유형 한정자로 표시된 숫자 (예 : 1L 또는 2.2d)

제공된 문자열이 null 또는 empty / blank 인 경우 숫자로 간주되지 않으며 메서드는 false 를 반환 합니다.

이 방법을 사용하여 몇 가지 테스트를 실행 해 보겠습니다.

assertThat(NumberUtils.isCreatable("22")).isTrue(); assertThat(NumberUtils.isCreatable("5.05")).isTrue(); assertThat(NumberUtils.isCreatable("-200")).isTrue(); assertThat(NumberUtils.isCreatable("10.0d")).isTrue(); assertThat(NumberUtils.isCreatable("1000L")).isTrue(); assertThat(NumberUtils.isCreatable("0xFF")).isTrue(); assertThat(NumberUtils.isCreatable("07")).isTrue(); assertThat(NumberUtils.isCreatable("2.99e+8")).isTrue(); assertThat(NumberUtils.isCreatable(null)).isFalse(); assertThat(NumberUtils.isCreatable("")).isFalse(); assertThat(NumberUtils.isCreatable("abc")).isFalse(); assertThat(NumberUtils.isCreatable(" 22 ")).isFalse(); assertThat(NumberUtils.isCreatable("09")).isFalse();

6, 7, 8 행에서 16 진수, 8 진수 및 과학적 표기법에 대한 진정한 단언을 얻는 방법에 유의하십시오 .

또한 14 행에서 문자열 "09" 는 앞의 "0" 이 이것이 8 진수이고 "09" 가 유효한 8 진수가 아님을 나타 내기 때문에 false를 반환합니다 .

이 메서드 로 true 를 반환하는 모든 입력에 대해 유효한 숫자를 제공하는 NumberUtils.createNumber (String) 를 사용할 수 있습니다.

5.2. NumberUtils.isParsable (문자열)

NumberUtils.isParsable (문자열) 에있어서 검사 주어진 여부 문자열 파싱 여부이다.

구문 분석 가능한 숫자는 Integer.parseInt (String) , Long.parseLong (String) , Float.parseFloat (String) 또는 Double.parseDouble (String) 과 같은 구문 분석 메서드에 의해 성공적으로 구문 분석 된 숫자 입니다.

NumberUtils.isCreatable () 과 달리이 메서드는 16 진수, 과학적 표기법 또는 유형 한정자로 끝나는 문자열 (즉, 'f', 'F', 'd', 'D', 'l' 또는 ')을 허용하지 않습니다. L ' .

몇 가지 확인 사항을 살펴 보겠습니다.

assertThat(NumberUtils.isParsable("22")).isTrue(); assertThat(NumberUtils.isParsable("-23")).isTrue(); assertThat(NumberUtils.isParsable("2.2")).isTrue(); assertThat(NumberUtils.isParsable("09")).isTrue(); assertThat(NumberUtils.isParsable(null)).isFalse(); assertThat(NumberUtils.isParsable("")).isFalse(); assertThat(NumberUtils.isParsable("6.2f")).isFalse(); assertThat(NumberUtils.isParsable("9.8d")).isFalse(); assertThat(NumberUtils.isParsable("22L")).isFalse(); assertThat(NumberUtils.isParsable("0xFF")).isFalse(); assertThat(NumberUtils.isParsable("2.99e+8")).isFalse();

4 행에서 NumberUtils.isCreatable () 과 달리 문자열 "0"으로 시작하는 숫자 는 8 진수로 간주되지 않지만 일반 10 진수이므로 true를 반환합니다.

이 방법을 섹션 3에서 수행 한 작업 대신 사용할 수 있습니다. 여기서 숫자를 구문 분석하고 오류를 확인하려고합니다.

5.3. StringUtils.isNumeric (CharSequence )

StringUtils.isNumeric (CharSequence) 메서드 는 유니 코드 숫자를 엄격하게 확인합니다. 이것은 다음을 의미합니다.

  1. 유니 코드 숫자 인 모든 언어의 모든 숫자가 허용됩니다.
  2. 소수점은 유니 코드 숫자로 간주되지 않으므로 유효하지 않습니다.
  3. 선행 기호 (양수 또는 음수)도 허용되지 않습니다.

이제이 메서드가 작동하는지 살펴 보겠습니다.

assertThat(StringUtils.isNumeric("123")).isTrue(); assertThat(StringUtils.isNumeric("١٢٣")).isTrue(); assertThat(StringUtils.isNumeric("१२३")).isTrue(); assertThat(StringUtils.isNumeric(null)).isFalse(); assertThat(StringUtils.isNumeric("")).isFalse(); assertThat(StringUtils.isNumeric(" ")).isFalse(); assertThat(StringUtils.isNumeric("12 3")).isFalse(); assertThat(StringUtils.isNumeric("ab2c")).isFalse(); assertThat(StringUtils.isNumeric("12.3")).isFalse(); assertThat(StringUtils.isNumeric("-123")).isFalse();

2 행과 3 행의 입력 매개 변수 는 아랍어와 데바 나가 리어로 각각 숫자 123 을 나타냅니다 . 유효한 유니 코드 숫자이므로이 메서드는 true 를 반환 합니다.

5.4. StringUtils.isNumericSpace(CharSequence)

The StringUtils.isNumericSpace(CharSequence) checks strictly for Unicode digits and/or space. This is same as StringUtils.isNumeric() with the only difference being that it accepts spaces as well, not only leading and trailing spaces but also if they're in between numbers:

assertThat(StringUtils.isNumericSpace("123")).isTrue(); assertThat(StringUtils.isNumericSpace("١٢٣")).isTrue(); assertThat(StringUtils.isNumericSpace("")).isTrue(); assertThat(StringUtils.isNumericSpace(" ")).isTrue(); assertThat(StringUtils.isNumericSpace("12 3")).isTrue(); assertThat(StringUtils.isNumericSpace(null)).isFalse(); assertThat(StringUtils.isNumericSpace("ab2c")).isFalse(); assertThat(StringUtils.isNumericSpace("12.3")).isFalse(); assertThat(StringUtils.isNumericSpace("-123")).isFalse();

6. Benchmarks

Before we conclude this article, let's go through some benchmark results to help us to analyze which of the above-mentioned methods are best for our use-case.

6.1. Simple Benchmark

First, we take a simple approach. We pick one string value – for our test we use Integer.MAX_VALUE. Then, that value will be tested against all our implementations:

Benchmark Mode Cnt Score Error Units Benchmarking.usingCoreJava avgt 20 57.241 ± 0.792 ns/op Benchmarking.usingNumberUtils_isCreatable avgt 20 26.711 ± 1.110 ns/op Benchmarking.usingNumberUtils_isParsable avgt 20 46.577 ± 1.973 ns/op Benchmarking.usingRegularExpressions avgt 20 101.580 ± 4.244 ns/op Benchmarking.usingStringUtils_isNumeric avgt 20 35.885 ± 1.691 ns/op Benchmarking.usingStringUtils_isNumericSpace avgt 20 31.979 ± 1.393 ns/op

As we see, the most costly operations are regular expressions. After that is our core Java-based solution.

Moreover, note that the operations using the Apache Commons library are by-and-large the same.

6.2. Enhanced Benchmark

Let's use a more diverse set of tests, for a more representative benchmark:

  • 95 values are numeric (0-94 and Integer.MAX_VALUE)
  • 3 contain numbers but are still malformatted — ‘x0‘, ‘0..005′, and ‘–11
  • 1 contains only text
  • 1 is a null

Upon executing the same tests, we'll see the results:

Benchmark Mode Cnt Score Error Units Benchmarking.usingCoreJava avgt 20 10162.872 ± 798.387 ns/op Benchmarking.usingNumberUtils_isCreatable avgt 20 1703.243 ± 108.244 ns/op Benchmarking.usingNumberUtils_isParsable avgt 20 1589.915 ± 203.052 ns/op Benchmarking.usingRegularExpressions avgt 20 7168.761 ± 344.597 ns/op Benchmarking.usingStringUtils_isNumeric avgt 20 1071.753 ± 8.657 ns/op Benchmarking.usingStringUtils_isNumericSpace avgt 20 1157.722 ± 24.139 ns/op

The most important difference is that two of our tests – the regular expressions solution and the core Java-based solution – have traded places.

이 결과를 통해 5 %의 경우에만 발생 하는 NumberFormatException 을 던지고 처리 하는 것이 전체 성능에 상대적으로 큰 영향을 미친다는 것을 알 수 있습니다. 따라서 최적의 솔루션은 예상 입력에 따라 달라진다는 결론을 내립니다.

또한 Commons 라이브러리의 방법이나 최적의 성능을 위해 유사하게 구현 된 방법을 사용해야한다고 안전하게 결론을 내릴 수 있습니다.

7. 결론

이 기사에서는 문자열 이 숫자인지 아닌지 를 찾는 다양한 방법을 탐색했습니다 . 우리는 두 가지 솔루션 (내장 방법과 외부 라이브러리)을 살펴 보았습니다.

항상 그렇듯이 벤치 마크를 수행하는 데 사용되는 코드를 포함하여 위에 제공된 모든 예제 및 코드 스 니펫의 구현은 GitHub에서 찾을 수 있습니다.