스트링이 Java의 정수를 나타내는 지 확인하는 가장 좋은 방법은 무엇입니까?
문제
일반적으로 다음 관용구를 사용하여 문자열을 정수로 변환 할 수 있는지 확인합니다.
public boolean isInteger( String input ) {
try {
Integer.parseInt( input );
return true;
}
catch( Exception e ) {
return false;
}
}
그것은 단지 나입니까, 아니면 이것이 약간 해킹 된 것처럼 보입니까? 더 좋은 방법은 무엇입니까?
내 대답을 참조하십시오 (벤치 마크와 함께 이전 답변 ~에 의해 코딩 스파이크) 왜 내가 내 입장을 취소하고 받아 들였는지 알아 보려면 Jonas Klemming의 답변 이 문제에. 이 원본 코드는 대부분의 사람들이 구현하기가 더 빠르고 유지 가능하기 때문에 대부분의 사람들이 사용될 것이라고 생각하지만, 비 인구 데이터가 제공 될 때는 몇 배 느립니다.
해결책
잠재적 인 오버플로 문제에 관심이없는 경우이 기능은 사용하는 것보다 약 20-30 배 더 빠르게 수행됩니다. Integer.parseInt()
.
public static boolean isInteger(String str) {
if (str == null) {
return false;
}
int length = str.length();
if (length == 0) {
return false;
}
int i = 0;
if (str.charAt(0) == '-') {
if (length == 1) {
return false;
}
i = 1;
}
for (; i < length; i++) {
char c = str.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
return true;
}
다른 팁
당신은 그것을 가지고 있지만 당신은 만 잡아야합니다 NumberFormatException
.
사람들이 여전히 여기를 방문하고 벤치 마크 후에도 Regex와의 편견이있을 가능성이 있기 때문에 ... 벤치 마크의 업데이트 된 버전을 제공합니다. 이전 벤치 마크와는 반대로,이 벤치 마크는 Regex 솔루션이 실제로 지속적으로 우수한 성능을 가지고 있음을 보여줍니다.
도마뱀에서 Bill에서 복사하고 컴파일 된 버전으로 업데이트되었습니다.
private final Pattern pattern = Pattern.compile("^-?\\d+$");
public void runTests() {
String big_int = "1234567890";
String non_int = "1234XY7890";
long startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByException(big_int);
long endTime = System.currentTimeMillis();
System.out.print("ByException - integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByException(non_int);
endTime = System.currentTimeMillis();
System.out.print("ByException - non-integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByRegex(big_int);
endTime = System.currentTimeMillis();
System.out.print("\nByRegex - integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByRegex(non_int);
endTime = System.currentTimeMillis();
System.out.print("ByRegex - non-integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++)
IsInt_ByCompiledRegex(big_int);
endTime = System.currentTimeMillis();
System.out.print("\nByCompiledRegex - integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for (int i = 0; i < 100000; i++)
IsInt_ByCompiledRegex(non_int);
endTime = System.currentTimeMillis();
System.out.print("ByCompiledRegex - non-integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByJonas(big_int);
endTime = System.currentTimeMillis();
System.out.print("\nByJonas - integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByJonas(non_int);
endTime = System.currentTimeMillis();
System.out.print("ByJonas - non-integer data: ");
System.out.println(endTime - startTime);
}
private boolean IsInt_ByException(String str)
{
try
{
Integer.parseInt(str);
return true;
}
catch(NumberFormatException nfe)
{
return false;
}
}
private boolean IsInt_ByRegex(String str)
{
return str.matches("^-?\\d+$");
}
private boolean IsInt_ByCompiledRegex(String str) {
return pattern.matcher(str).find();
}
public boolean IsInt_ByJonas(String str)
{
if (str == null) {
return false;
}
int length = str.length();
if (length == 0) {
return false;
}
int i = 0;
if (str.charAt(0) == '-') {
if (length == 1) {
return false;
}
i = 1;
}
for (; i < length; i++) {
char c = str.charAt(i);
if (c <= '/' || c >= ':') {
return false;
}
}
return true;
}
결과:
ByException - integer data: 45
ByException - non-integer data: 465
ByRegex - integer data: 272
ByRegex - non-integer data: 131
ByCompiledRegex - integer data: 45
ByCompiledRegex - non-integer data: 26
ByJonas - integer data: 8
ByJonas - non-integer data: 2
빠른 벤치 마크를했습니다. 여러 메소드를 튀어 나오기 시작하고 JVM이 실행 스택을 마련하기 위해 많은 작업을 수행해야하지 않는 한 예외는 실제로 그 지압이 아닙니다. 같은 방법으로 머무를 때는 나쁜 공연자가 아닙니다.
public void RunTests()
{
String str = "1234567890";
long startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByException(str);
long endTime = System.currentTimeMillis();
System.out.print("ByException: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByRegex(str);
endTime = System.currentTimeMillis();
System.out.print("ByRegex: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByJonas(str);
endTime = System.currentTimeMillis();
System.out.print("ByJonas: ");
System.out.println(endTime - startTime);
}
private boolean IsInt_ByException(String str)
{
try
{
Integer.parseInt(str);
return true;
}
catch(NumberFormatException nfe)
{
return false;
}
}
private boolean IsInt_ByRegex(String str)
{
return str.matches("^-?\\d+$");
}
public boolean IsInt_ByJonas(String str)
{
if (str == null) {
return false;
}
int length = str.length();
if (length == 0) {
return false;
}
int i = 0;
if (str.charAt(0) == '-') {
if (length == 1) {
return false;
}
i = 1;
}
for (; i < length; i++) {
char c = str.charAt(i);
if (c <= '/' || c >= ':') {
return false;
}
}
return true;
}
산출:
학습 : 31
ByRegex : 453 (참고 : 매번 패턴을 재 컴파일)
Byjonas : 16
Jonas K의 솔루션이 가장 강력하다는 데 동의합니다. 그가이기는 것 같습니다 :)
org.apache.commons.lang.StringUtils.isNumeric
Java의 표준 lib는 실제로 그러한 유틸리티 기능을 놓치지 만
Apache Commons는 모든 Java 프로그래머에 대해 "필수"라고 생각합니다.
너무 나쁘다. 그것은 아직 Java5로 포팅되지 않았다
그것은 부분적으로 "정수로 변환 될 수있다"는 의미에 따라 다릅니다.
"Java의 int로 변환 될 수있다"는 의미가 있다면 Jonas의 답변은 좋은 출발이지만 작업을 끝내지 않습니다. 예를 들어 99999999999999999999999999999를 통과합니다. 메소드가 끝날 때 자신의 질문에서 일반적인 시도/캐치 콜을 추가합니다.
문자 별 문자 검사는 "정수가 아닌"케이스를 효율적으로 거부 할 것입니다. 너 ~할 수 있었다 이 비트도 손으로 수행하지만 많은 더 복잡한.
Regexp에 대한 단 하나의 의견. 여기에 제공된 모든 예제가 잘못되었습니다!. regexp를 사용하려면 패턴을 컴파일하는 데 많은 시간이 걸린다는 것을 잊지 마십시오. 이것:
str.matches("^-?\\d+$")
그리고 이것도 :
Pattern.matches("-?\\d+", input);
모든 메소드 호출에서 패턴의 컴파일을 유발합니다. 올바르게 사용하려면 다음과 같습니다.
import java.util.regex.Pattern;
/**
* @author Rastislav Komara
*/
public class NaturalNumberChecker {
public static final Pattern PATTERN = Pattern.compile("^\\d+$");
boolean isNaturalNumber(CharSequence input) {
return input != null && PATTERN.matcher(input).matches();
}
}
Rally25RS 답변에서 코드를 복사하고 비 integer 데이터에 대한 테스트를 추가했습니다. 결과는 Jonas Klemming이 게시 한 방법에 유리하게 나타납니다. 내가 원래 게시 한 예외 방법의 결과는 정수 데이터를 가지고있을 때 꽤 좋지만, 그렇지 않은 경우 최악의 경우, Regex 솔루션의 결과 (많은 사람들이 사용 할 것입니다). ~이었다 일관되게 나쁜. 보다 펠리페의 대답 컴파일 된 Regex 예제의 경우 훨씬 빠릅니다.
public void runTests()
{
String big_int = "1234567890";
String non_int = "1234XY7890";
long startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByException(big_int);
long endTime = System.currentTimeMillis();
System.out.print("ByException - integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByException(non_int);
endTime = System.currentTimeMillis();
System.out.print("ByException - non-integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByRegex(big_int);
endTime = System.currentTimeMillis();
System.out.print("\nByRegex - integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByRegex(non_int);
endTime = System.currentTimeMillis();
System.out.print("ByRegex - non-integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByJonas(big_int);
endTime = System.currentTimeMillis();
System.out.print("\nByJonas - integer data: ");
System.out.println(endTime - startTime);
startTime = System.currentTimeMillis();
for(int i = 0; i < 100000; i++)
IsInt_ByJonas(non_int);
endTime = System.currentTimeMillis();
System.out.print("ByJonas - non-integer data: ");
System.out.println(endTime - startTime);
}
private boolean IsInt_ByException(String str)
{
try
{
Integer.parseInt(str);
return true;
}
catch(NumberFormatException nfe)
{
return false;
}
}
private boolean IsInt_ByRegex(String str)
{
return str.matches("^-?\\d+$");
}
public boolean IsInt_ByJonas(String str)
{
if (str == null) {
return false;
}
int length = str.length();
if (length == 0) {
return false;
}
int i = 0;
if (str.charAt(0) == '-') {
if (length == 1) {
return false;
}
i = 1;
}
for (; i < length; i++) {
char c = str.charAt(i);
if (c <= '/' || c >= ':') {
return false;
}
}
return true;
}
결과:
ByException - integer data: 47
ByException - non-integer data: 547
ByRegex - integer data: 390
ByRegex - non-integer data: 313
ByJonas - integer data: 0
ByJonas - non-integer data: 16
구아바 버전이 있습니다.
import com.google.common.primitives.Ints;
Integer intValue = Ints.tryParse(stringValue);
문자열을 구문 분석하지 못하면 예외를 던지지 않고 NULL을 반환합니다.
이것은 짧지 만 짧게 더 나은 것은 아닙니다 (그리고 범위를 벗어난 정수 값을 잡을 수는 없습니다. 다나텔의 의견에서 지적한 바와 같이):
input.matches("^-?\\d+$");
개인적으로, 구현은 도우미 방법과 정확성이 우선하는 길이로 다람관되기 때문에, 나는 당신이 가진 것과 같은 것을 가지고 갈 것입니다 (베이스를 잡는 마이너스 Exception
수업보다는 NumberFormatException
).
문자열 클래스의 일치 메소드를 사용할 수 있습니다. [0-9]는 모든 값을 나타내고, +는 그것이 하나 이상의 문자 길이 여야한다는 것을 의미하며, *는 0 이상이 될 수 있음을 의미합니다.
boolean isNumeric = yourString.matches("[0-9]+"); // 1 or more characters long, numbers only
boolean isNumeric = yourString.matches("[0-9]*"); // 0 or more characters long, numbers only
이것은 Jonas Klemming의 Java 8 변형입니다.
public static boolean isInteger(String str) {
return str != null && str.length() > 0 &&
IntStream.range(0, str.length()).allMatch(i -> i == 0 && (str.charAt(i) == '-' || str.charAt(i) == '+')
|| Character.isDigit(str.charAt(i)));
}
테스트 코드 :
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
Arrays.asList("1231231", "-1232312312", "+12313123131", "qwqe123123211", "2", "0000000001111", "", "123-", "++123",
"123-23", null, "+-123").forEach(s -> {
System.out.printf("%15s %s%n", s, isInteger(s));
});
}
테스트 코드의 결과 :
1231231 true
-1232312312 true
+12313123131 true
qwqe123123211 false
2 true
0000000001111 true
false
123- false
++123 false
123-23 false
null false
+-123 false
문자열 배열에 순수한 정수와 문자열이 포함 된 경우 아래 코드는 작동해야합니다. 당신은 첫 번째 캐릭터를 보면됩니다. 예 : [ "4", "44", "ABC", "77", "Bond"]]
if (Character.isDigit(string.charAt(0))) {
//Do something with int
}
당신은 또한 사용할 수 있습니다 스캐너 수업 및 사용 hasnextint () - 이렇게하면 플로트 등과 같은 다른 유형을 테스트 할 수 있습니다.
어때요 :
return Pattern.matches("-?\\d+", input);
당신은 그냥 확인합니다 숫자 formatexception:-
String value="123";
try
{
int s=Integer.parseInt(any_int_val);
// do something when integer values comes
}
catch(NumberFormatException nfe)
{
// do something when string values comes
}
유스 케이스를 계정으로 가져 가야 할 것입니다.
대부분의 시간이 숫자가 유효 할 것으로 예상되는 경우 예외를 포착하면 유효하지 않은 숫자를 변환하려고 할 때만 성능 오버 헤드 만 발생합니다. 일부 전화 isInteger()
방법을 사용하여 사용합니다 Integer.parseInt()
~ 할 것이다 언제나 유효한 숫자에 대한 성능 오버 헤드를 유발합니다. 문자열은 수표에 의해 한 번, 변환에 의해 두 번 구문 분석됩니다.
이것은 수정입니다 조나스'문자열이 범위 내에 있는지 확인하는 코드.
public static boolean isInteger(String str) {
if (str == null) {
return false;
}
int length = str.length();
int i = 0;
// set the length and value for highest positive int or lowest negative int
int maxlength = 10;
String maxnum = String.valueOf(Integer.MAX_VALUE);
if (str.charAt(0) == '-') {
maxlength = 11;
i = 1;
maxnum = String.valueOf(Integer.MIN_VALUE);
}
// verify digit length does not exceed int range
if (length > maxlength) {
return false;
}
// verify that all characters are numbers
if (maxlength == 11 && length == 1) {
return false;
}
for (int num = i; num < length; num++) {
char c = str.charAt(num);
if (c < '0' || c > '9') {
return false;
}
}
// verify that number value is within int range
if (length == maxlength) {
for (; i < length; i++) {
if (str.charAt(i) < maxnum.charAt(i)) {
return true;
}
else if (str.charAt(i) > maxnum.charAt(i)) {
return false;
}
}
}
return true;
}
Android API를 사용하는 경우 사용할 수 있습니다.
TextUtils.isDigitsOnly(str);
다른 옵션 :
private boolean isNumber(String s) {
boolean isNumber = true;
for (char c : s.toCharArray()) {
isNumber = isNumber && Character.isDigit(c);
}
return isNumber;
}
문자열이 int 유형에 맞는 정수를 나타내는 지 확인하려면 Jonas의 대답을 약간 수정하여 정수보다 더 큰 정수를 나타내는 문자열이 integer.min_value보다 작습니다. 거짓. 예를 들어 : "3147483647"은 2147483647보다 크기 때문에 "3147483647"은 False를 반환합니다. 마찬가지로 -2147483649는 -2147483649보다 -2147483648보다 작기 때문에 "-2147483649"도 거짓을 반환합니다.
public static boolean isInt(String s) {
if(s == null) {
return false;
}
s = s.trim(); //Don't get tricked by whitespaces.
int len = s.length();
if(len == 0) {
return false;
}
//The bottom limit of an int is -2147483648 which is 11 chars long.
//[note that the upper limit (2147483647) is only 10 chars long]
//Thus any string with more than 11 chars, even if represents a valid integer,
//it won't fit in an int.
if(len > 11) {
return false;
}
char c = s.charAt(0);
int i = 0;
//I don't mind the plus sign, so "+13" will return true.
if(c == '-' || c == '+') {
//A single "+" or "-" is not a valid integer.
if(len == 1) {
return false;
}
i = 1;
}
//Check if all chars are digits
for(; i < len; i++) {
c = s.charAt(i);
if(c < '0' || c > '9') {
return false;
}
}
//If we reached this point then we know for sure that the string has at
//most 11 chars and that they're all digits (the first one might be a '+'
// or '-' thought).
//Now we just need to check, for 10 and 11 chars long strings, if the numbers
//represented by the them don't surpass the limits.
c = s.charAt(0);
char l;
String limit;
if(len == 10 && c != '-' && c != '+') {
limit = "2147483647";
//Now we are going to compare each char of the string with the char in
//the limit string that has the same index, so if the string is "ABC" and
//the limit string is "DEF" then we are gonna compare A to D, B to E and so on.
//c is the current string's char and l is the corresponding limit's char
//Note that the loop only continues if c == l. Now imagine that our string
//is "2150000000", 2 == 2 (next), 1 == 1 (next), 5 > 4 as you can see,
//because 5 > 4 we can guarantee that the string will represent a bigger integer.
//Similarly, if our string was "2139999999", when we find out that 3 < 4,
//we can also guarantee that the integer represented will fit in an int.
for(i = 0; i < len; i++) {
c = s.charAt(i);
l = limit.charAt(i);
if(c > l) {
return false;
}
if(c < l) {
return true;
}
}
}
c = s.charAt(0);
if(len == 11) {
//If the first char is neither '+' nor '-' then 11 digits represent a
//bigger integer than 2147483647 (10 digits).
if(c != '+' && c != '-') {
return false;
}
limit = (c == '-') ? "-2147483648" : "+2147483647";
//Here we're applying the same logic that we applied in the previous case
//ignoring the first char.
for(i = 1; i < len; i++) {
c = s.charAt(i);
l = limit.charAt(i);
if(c > l) {
return false;
}
if(c < l) {
return true;
}
}
}
//The string passed all tests, so it must represent a number that fits
//in an int...
return true;
}
is_number = true;
try {
Integer.parseInt(mystr)
} catch (NumberFormatException e) {
is_number = false;
}
당신이 한 일은 작동하지만 항상 그런 식으로 확인해서는 안됩니다. 던지기 예외는 "예외적 인"상황에 대해 예약되어야하며 (아마도 당신의 경우에 적합 할 수도 있음) 성능 측면에서 비용이 많이 듭니다.
Number number;
try {
number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
//not a number - do recovery.
e.printStackTrace();
}
//use number
이것은 긍정적 인 정수에만 적용됩니다.
public static boolean isInt(String str) {
if (str != null && str.length() != 0) {
for (int i = 0; i < str.length(); i++) {
if (!Character.isDigit(str.charAt(i))) return false;
}
}
return true;
}
이것은 나를 위해 작동합니다. 문자열이 원시적인지 숫자인지 확인하기 위해 간단합니다.
private boolean isPrimitive(String value){
boolean status=true;
if(value.length()<1)
return false;
for(int i = 0;i<value.length();i++){
char c=value.charAt(i);
if(Character.isDigit(c) || c=='.'){
}else{
status=false;
break;
}
}
return status;
}
모든 int char를 확인하려면 이중 네거티브를 사용할 수 있습니다.
if (! searchString.matches ( [^0-9]+$")) ...
^0-9]+$ 수표는 정수가 아닌 문자가 있는지 확인하므로 테스트가 사실이면 실패합니다. 그건 그냥 아니고 당신은 성공에 맞습니다.
도움이 될 수 있습니다.
public static boolean isInteger(String self) {
try {
Integer.valueOf(self.trim());
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
아래에서 볼 수 있듯이 항상 안전하게 구문 분석하기 때문에 예외가 발생할 위험이 없습니다. int
에게 String
그리고 다른 방법은 아닙니다.
그래서:
너 확인하다 문자열의 모든 문자 슬롯이 문자 중 하나 이상 일치하는 경우 {"0","1","2","3","4","5","6","7","8","9"}.
if(aString.substring(j, j+1).equals(String.valueOf(i)))
너 합집합 당신이 슬롯에서 만난 모든 시간은 위의 문자입니다.
digits++;
그리고 마침내 당신 확인하다 문자로 정수를 만난 시간이 주어진 문자열의 길이와 동일합니다.
if(digits == aString.length())
그리고 실제로 우리는 다음과 같습니다.
String aString = "1234224245";
int digits = 0;//count how many digits you encountered
for(int j=0;j<aString.length();j++){
for(int i=0;i<=9;i++){
if(aString.substring(j, j+1).equals(String.valueOf(i)))
digits++;
}
}
if(digits == aString.length()){
System.out.println("It's an integer!!");
}
else{
System.out.println("It's not an integer!!");
}
String anotherString = "1234f22a4245";
int anotherDigits = 0;//count how many digits you encountered
for(int j=0;j<anotherString.length();j++){
for(int i=0;i<=9;i++){
if(anotherString.substring(j, j+1).equals(String.valueOf(i)))
anotherDigits++;
}
}
if(anotherDigits == anotherString.length()){
System.out.println("It's an integer!!");
}
else{
System.out.println("It's not an integer!!");
}
그리고 결과는 다음과 같습니다.
정수입니다 !!
정수가 아닙니다 !!
마찬가지로 a String
a float
또는 a double
그러나 그러한 경우에 당신은 만나야합니다 단 하나. (dot) 문자열에서 물론 digits == (aString.length()-1)
다시 말하지만, 여기에는 구문 분석 예외가 발생할 위험이 없습니다. 그러나 숫자가 포함 된 문자열을 구문 분석 할 계획이라면 ( int 데이터 유형) 먼저 데이터 유형에 맞는지 확인해야합니다. 그렇지 않으면 캐스트해야합니다.
내가 도와 주셨으면 좋겠다