Обычно я использую следующую идиому, чтобы проверить, можно ли преобразовать String в целое число.
public boolean isInteger( String input ) {
try {
Integer.parseInt( input );
return true;
}
catch( Exception e ) {
return false;
}
}
Это только мне кажется, или это кажется немного взломанным? Что лучше?
См. Мой ответ (с тестами, основанными на предыдущий ответ от CodingWithSpike), чтобы понять, почему я изменил свою позицию и принял Ответ Йонаса Клемминга для решения этой проблемы. Я думаю, что этот исходный код будет использоваться большинством людей, потому что его быстрее реализовать и легче поддерживать, но он на несколько порядков медленнее, когда предоставляются нецелочисленные данные.




Как насчет:
return Pattern.matches("-?\\d+", input);
А как насчет целого числа 99999999999999999999999999999999?
Не забудьте проверить наличие отрицательного знака.
разве вам не нужно привязывать начало и конец регулярного выражения, чтобы вы не передавали "aaa-1999zzz"?
Тим, когда вы вызываете один из методов match () (каждый из которых имеет String, Pattern и Matcher), регулярное выражение должно соответствовать всему вводу, что делает якоря избыточными. Чтобы найти совпадение, как определено в большинстве других разновидностей регулярных выражений, вы должны использовать Matcher # find ().
Он у вас есть, но вы должны ловить только NumberFormatException.
Ага, ловить больше исключений, чем нужно, считается дурным тоном.
Ты прав. NFE - единственное, что можно бросить, но это все еще плохая привычка.
Я думаю, что NPE может быть запущен, если input имеет значение null, поэтому ваш метод, вероятно, должен обрабатывать это явно, как вы хотите.
@Dov: Вы правы, NPE и NFE должны быть явно пойманы.
Этот ответ должен быть верным ответом на этот вопрос.
На мой взгляд, эта последовательность комментариев на самом деле представляет собой хороший случай, когда для ловит java.lang.Exception (или Throwable), демонстрируя, как очень легко пропустить один.
Проголосуйте против, потому что перехват исключений противоположен коду для повышения производительности: P
Это короче, но короче не обязательно лучше (и он не будет улавливать целочисленные значения, выходящие за пределы диапазона, как указано в комментарии Данателя):
input.matches("^-?\\d+$");
Лично, поскольку реализация реализована во вспомогательном методе, а правильность превосходит длину, я бы просто выбрал что-то вроде того, что у вас есть (за вычетом базового класса Exception, а не NumberFormatException).
И, возможно, \\ d {1,10}, хотя и не идеальный, лучше, чем \\ d + для отлова целых чисел Java.
То, что вы сделали, работает, но вам, вероятно, не всегда следует так проверять. Выбрасывание исключений должно быть зарезервировано для «исключительных» ситуаций (хотя, возможно, это подходит для вашего случая), и это очень дорого с точки зрения производительности.
Они обходятся дорого только в том случае, если их бросают.
Если вас не беспокоят проблемы с переполнением, эта функция будет работать примерно в 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;
}
(c <= '/' || c> = ':') выглядит немного странно. Я бы использовал (c <'0' || c> '9') ... операторы <= и> = быстрее в Java?
Почему бы не использовать регулярное выражение? Разве return str.matches ("^ -? \\ d + $") не идентичен приведенному выше коду.
Я бы использовал этот метод или исходный метод из вопроса перед регулярным выражением. Это для производительности, оригинальный метод для скорости внедрения и простой ремонтопригодности. Решение с регулярным выражением ничего не подходит.
Меня беспокоит переполнение, но этот метод можно адаптировать для BigInts и при этом он будет намного быстрее, чем другие методы. Если кому-то интересно, почему я вкладываю столько усилий в решение такой простой проблемы, я создаю библиотеку, чтобы помочь в решении проблем Project Euler.
Если вас беспокоит, действительно ли вы можете преобразовать строку в int или long, вам также нужно будет проверить, действительно ли целое число, которое представляет строка, соответствует этим типам данных.
Обратите внимание, что эта функция намного быстрее, но, в конце концов, у вас нет целого числа! Если вы собираетесь использовать результат для фактического преобразования строки, прирост производительности не так важен, если ситуация «исключительная».
Разве это не вернет True, если str == "a123"?
Как вы проверяете строки, начинающиеся с «0»?
@Bill: Не совсем верно, что решение с регулярным выражением ничего не подходит. Он использует класс \d, что позволяет избежать зависимостей как от цифровых символов (например, «0» и «9» против персидских цифр), так и от их порядка (сравнение <>). Эти зависимости на самом деле хрупкие, как вы увидите, когда появятся ваши целые числа, похожие на ۵۷۱۰. Регулярное выражение может действительно работать из коробки, если языковой стандарт установлен правильно.
Первые строки для проверки того, является ли "str" нулевым или пустым, можно заменить на TextUtils.isEmpty (str). TextUtils является частью SDK и делает то же самое.
Зависит. "2.00" = 2? Для компьютеров обычно нет. Для математиков и людей, которые изучали математику в средней школе, да. Следовательно, приведенный выше ответ слабый. А как насчет «2»? или ".00"? Ниже вы узнаете, как справляться с подобными ситуациями.
Как и в случае с любым методом фильтрации, если у вас небольшое количество ложных срабатываний, а само количество срабатываний намного меньше количества отрицательных ответов, вы всегда можете провести более полную проверку после быстрой проверки. (примечание - положительные = ответы с логическим результатом «истина»; отрицательные = ответы с логическим результатом «ложь»).
@Tihamer А как насчет научных обозначений? А как насчет восьмеричных или шестнадцатеричных чисел? А как насчет таких выражений, как 2 + 2, которое можно упростить до 4? И так далее. Этот ответ прекрасен, учитывая то, что он решает (простые целочисленные значения без учета переполнения).
когда ввод - это один единственный оператор, такой как "*", функция также вернет true ...
Integer.valueOf(string);
у меня работает большую часть времени!
Это (все - большую часть) времени меня беспокоит. :)
Сделал быстрый тест. На самом деле исключения не так уж и дороги, если только вы не начнете возвращать несколько методов, и 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;
}
Выход:
ByException: 31
ByRegex: 453 (note: re-compiling the pattern every time)
ByJonas: 16
Я согласен с тем, что решение Йонаса К. также является самым надежным. Похоже, он выигрывает :)
Отличная идея протестировать все три. Чтобы быть справедливым по отношению к методам Regex и Jonas, вы должны тестировать нецелочисленные строки, поскольку именно там метод Integer.parseInt действительно замедлится.
Извините, но этот тест с регулярным выражением не подходит. (1) Вам не нужно выполнять проверку движка регулярных выражений для ^ и $ второй раз, поскольку в matches вся строка должна соответствовать регулярному выражению, (2) str.matches каждый раз должен будет создавать свой собственный Pattern, что дорого. По соображениям производительности мы должны создать такой Pattern только один раз вне этого метода и использовать его внутри. (3) Мы также можем создать только один объект Matcher и использовать его reset(CharSequence) для передачи пользовательских данных и возврата результата matches().
Так что что-то вроде private final Matcher m = Pattern.compile("-?\\d+").matcher(""); private boolean byRegex(String str) { return m.reset(str).matches(); } должно иметь лучшую производительность.
@Pshemo Integer.valueOf ("1") и Integer.valueOf ("1") генерируют исключение, поэтому проверка на ^ и $ кажется разумной.
@cquezel Да, но это не требуется, поскольку matches неявно добавляет ^ и $. Взгляните на результат " 123".matches("\\d+") и "123".matches("\\d+"). Вы увидите false и true. false будет возвращен, потому что строка начинается с пробела, что предотвращает полное совпадение с регулярным выражением.
Вы также можете использовать класс Сканер и использовать hasNextInt () - и это позволяет вам тестировать и другие типы, такие как поплавки и т. д.
Этот ответ напомнил мне, что мне нужно. Я совсем забыл, что у Сканера есть такая функция. Футболка
Отчасти это зависит от того, что вы имеете в виду под «может быть преобразовано в целое число».
Если вы имеете в виду «можно преобразовать в int в Java», то ответ Джонаса - хорошее начало, но не совсем завершение работы. Например, он будет проходить 999999999999999999999999999999. Я бы добавил обычный вызов try / catch из вашего собственного вопроса в конце метода.
Посимвольные проверки будут эффективно отклонять случаи «вообще не целое число», оставляя случаи «это целое число, но Java не может его обработать», которые будут перехвачены более медленным маршрутом исключения. Вы, мог, тоже делаете это вручную, но это будет более сложный много.
Number number;
try {
number = NumberFormat.getInstance().parse("123");
} catch (ParseException e) {
//not a number - do recovery.
e.printStackTrace();
}
//use number
Всего один комментарий о регулярном выражении. Каждый приведенный здесь пример неверен !. Если вы хотите использовать регулярное выражение, не забывайте, что компиляция шаблона занимает много времени. Этот:
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();
}
}
Вы можете добиться немного большей производительности, заранее создав Matcher и применив его метод reset () к входным данным.
Я скопировал код из ответа rally25rs и добавил несколько тестов для нецелочисленных данных. Результаты, несомненно, свидетельствуют в пользу метода, опубликованного Йонасом Клеммингом. Результаты для метода Exception, который я изначально опубликовал, довольно хороши, когда у вас есть целочисленные данные, но они худшие, когда у вас их нет, в то время как результаты для решения 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
org.apache.commons.lang.StringUtils.isNumeric
хотя стандартная библиотека Java действительно пропускает такие служебные функции
Я считаю, что Apache Commons просто необходим каждому программисту на Java.
жаль, что он еще не портирован на Java5
Единственная проблема с этим - переполнение: S Я все еще даю вам +1 за упоминание commons-lang :)
Другая проблема - отрицательные числа, но я также +1, поскольку, на мой взгляд, этот подход ближе всего к хорошему решению.
Поскольку есть вероятность, что люди все еще будут сюда заходить и будут предвзято относиться к Regex после тестов ... Итак, я дам обновленную версию теста с скомпилированной версией Regex. В отличие от предыдущих тестов, этот показывает, что решение Regex действительно имеет стабильно хорошую производительность.
Скопировано из Bill the Lizard и обновлено скомпилированной версией:
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
Время ByCompiledRegex должно включать компиляцию регулярного выражения в его измерение времени.
@MartinCarney Я модифицировал его и протестировал компиляцию паттернов. Очевидно, мой CPU / JIT быстрее, но если я интерполирую его обратно, время компиляции будет 336.
Чтобы было ясно, что 336 (мс) - это то, что происходит, когда компиляция шаблона выполняется 100k раз, как и все другие строки. Подразумевая, что это делается только один раз, его время в основном равно нулю.
Спасибо, что установили рекорд времени скомпилированного регулярного выражения.
Может быть, "^[+-]?\\d+$" был бы даже лучше.
Это будет работать только для положительных целых чисел.
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;
}
Добро пожаловать в stackoverflow. Перед тем, как воскресить старую ветку, обязательно прочтите предыдущие ответы и комментарии. Этот метод (и возможные недостатки) фактически уже обсуждался.
Вероятно, вам также нужно принять во внимание вариант использования:
Если в большинстве случаев вы ожидаете, что числа будут действительными, то перехват исключения приводит только к снижению производительности при попытке преобразовать недопустимые числа. В то время как вызов некоторого метода isInteger() и последующее преобразование с использованием Integer.parseInt() приведет к увеличению производительности всегда для действительных чисел - строки анализируются дважды, один раз проверкой и один раз преобразованием.
Вы можете использовать метод совпадений строкового класса. [0-9] представляет все возможные значения, + означает, что он должен состоять как минимум из одного символа, а * означает, что он может содержать ноль или более символов.
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
Nb, это не соответствует "+10" или "-10"), которые обычно включаются как действительные целые числа.
Просто проверьте NumberFormatException: -
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
}
Вы можете попробовать apache utils
NumberUtils.isCreatable(myText)
Похоже, этот метод устарел в последней версии связь). По-видимому, вам следует использовать вместо этого isCreateable(String).
Обновлено. Спасибо @Guildenstern
Если ваш массив String содержит чистые целые числа и строки, приведенный ниже код должен работать. Вам нужно только посмотреть на первого персонажа. например [«4», «44», «abc», «77», «облигация»]
if (Character.isDigit(string.charAt(0))) {
//Do something with int
}
Для тех читателей, которые приходят сюда, как и я, спустя годы после того, как вопрос был задан, у меня есть более общее решение этого вопроса.
/**
* Checks, if the string represents a number.
*
* @param string the string
* @return true, if the string is a number
*/
public static boolean isANumber(final String string) {
if (string != null) {
final int length = string.length();
if (length != 0) {
int i = 0;
if (string.charAt(0) == '-') {
if (length == 1) {
return false;
}
i++;
}
for (; i < length; i++) {
final char c = string.charAt(i);
if ((c <= PERIOD) || ((c >= COLON))) {
final String strC = Character.toString(c).toUpperCase();
final boolean isExponent = strC.equals("E");
final boolean isPeriod = (c == PERIOD);
final boolean isPlus = (c == PLUS);
if (!isExponent && !isPeriod && !isPlus) {
return false;
}
}
}
return true;
}
}
return false;
}
Try / catch предназначен для использования, когда вы действительно не контролируете, что может пойти не так. В этом случае - можете, и принятый ответ по-прежнему остается хорошим решением. Кроме того, создание исключений обходится дорого, и этого следует избегать.
Это модификация кода Йонас ', которая проверяет, находится ли строка в пределах диапазона, который нужно преобразовать в целое число.
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;
}
выглядит хорошо, но в последнем цикле for необходимо сбросить i до нуля (или 1, если число отрицательное), потому что цикл, который проверяет, является ли каждая цифра числом, приведет к тому, что i будет длиной строки, поэтому последний цикл for никогда не побегу. Я бы также использовал константы Java Integer.MAX_VALUE и Integer.MIN_VALUE вместо магических чисел.
@TimtheEnchanter Спасибо за предложения, я их полностью упустил. В моем редактировании, чтобы включить их, я использовал новую переменную в первом цикле for, чтобы избежать лишнего оператора if.
У меня это работает. Просто чтобы определить, является ли String примитивом или числом.
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, вы можете просто использовать двойное отрицание.
если (! searchString.matches ("[^ 0-9] + $")) ...
[^ 0-9] + $ проверяет, есть ли какие-либо символы, которые не являются целыми числами, поэтому тест не выполняется, если это правда. Только НЕ это, и вы получите правду в случае успеха.
Нет. Вы явно не проверяли это. Это возвращает истину, только если где-то в строке есть цифра, а не если строка состоит только из цифр. Метод matches сопоставляется со всей строкой, а не только с ее частью.
Вы не получите двойной отрицательной части.
Ну, я НЕ получаю двойного негатива. Это просто не работает. Если у вас есть смесь цифр и букв, они попадают в блок if. Не должно.
Я считаю, что нет никакого риска столкнуться с исключением, потому что, как вы можете видеть ниже, вы всегда безопасно разбираете 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!!");
}
И вот результаты:
It's an integer!!
It's not an integer!!
Точно так же вы можете проверить, является ли Stringfloat или double, но в этих случаях вы должны встретить только один . (точка) в строке и, конечно, проверить, является ли digits == (aString.length()-1)
Again, there's zero risk running into a parsing exception here, but if you plan on parsing a string that it is known that contains a number (let's say int data type) you must first check if it fits in the data type. Otherwise you must cast it.
Надеюсь я помог
Это может быть полезно:
public static boolean isInteger(String self) {
try {
Integer.valueOf(self.trim());
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
Если вы используете Android API, вы можете использовать:
TextUtils.isDigitsOnly(str);
Есть версия гуавы:
import com.google.common.primitives.Ints;
Integer intValue = Ints.tryParse(stringValue);
Он вернет значение null вместо того, чтобы генерировать исключение, если не удалось проанализировать строку.
Лучший ответ ИМХО. Используйте хорошо протестированные библиотеки вместо того, чтобы создавать собственное решение. (Также см. Обсуждение здесь.)
public class HelloWorld{
static boolean validateIP(String s){
String[] value = s.split("\\.");
if (value.length!=4) return false;
int[] v = new int[4];
for(int i=0;i<4;i++){
for(int j=0;j<value[i].length();j++){
if (!Character.isDigit(value[i].charAt(j)))
return false;
}
v[i]=Integer.parseInt(value[i]);
if (!(v[i]>=0 && v[i]<=255)) return false;
}
return true;
}
public static void main(String[] argv){
String test = "12.23.8.9j";
if (validateIP(test)){
System.out.println(""+test);
}
}
}
При чем тут IP-адрес?
Другой вариант:
private boolean isNumber(String s) {
boolean isNumber = true;
for (char c : s.toCharArray()) {
isNumber = isNumber && Character.isDigit(c);
}
return isNumber;
}
Я видел здесь много ответов, но большинство из них могут определить, является ли String числовым, но они не проверяют, находится ли число в целочисленном диапазоне ...
Поэтому я намерен сделать что-то вроде этого:
public static boolean isInteger(String str) {
if (str == null || str.isEmpty()) {
return false;
}
try {
long value = Long.valueOf(str);
return value >= -2147483648 && value <= 2147483647;
} catch (Exception ex) {
return false;
}
}
Хороший момент, обрабатывается com.google.common.primitives.Ints.tryParse (String, int), предложенным в ответе Guava.
Но у строкового значения тоже есть шанс выйти за пределы длинного лимита. Как мы можем предположить, что это далеко. Например, строка также может содержать это значение 9 223 372 036 854 775 809, но long не может, и в этом случае мы получаем исключение NumberFormatException.
Метод должен проверить, находится ли значение, представленное String, в диапазоне Integer. Если вы предоставите методу аргумент, который даже больше, чем Long, то это определенно не целое число, и метод должен вернуть «false». Что и происходит, поскольку при преобразовании возникает ошибка, а в предложении catch указывается значение false.
Это вариант 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
Если вы хотите проверить, представляет ли строка целое число, подходящее для типа int, я немного изменил ответ jonas, чтобы строки, представляющие целые числа больше Integer.MAX_VALUE или меньше Integer.MIN_VALUE, теперь возвращали ложный. Например: «3147483647» вернет false, потому что 3147483647 больше, чем 2147483647, и аналогично «-2147483649» также вернет false, потому что -2147483649 меньше, чем -2147483648.
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;
}
не могли бы вы отредактировать свой ответ и объяснить, как он улучшает предыдущий ответ, который вы упомянули?
Спасибо за отличный ответ. Но «123», то есть 123 вместе с пробелом, считается действительным целым числом.
@SaikrishnaRadarapu Они используют trim(), так что это явно намеренный выбор дизайна.
Когда объяснения важнее производительности
Я заметил много дискуссий о том, насколько эффективны определенные решения, но в Почему ни одна строка не является целым числом. Кроме того, все, казалось, полагали, что число «2,00» не равно «2». С математической и человеческой точки зрения они равны являются (хотя компьютерные науки говорят, что это не так, и не зря). Вот почему решения "Integer.parseInt" выше слабые (в зависимости от ваших требований).
В любом случае, чтобы сделать программное обеспечение более умным и удобным для человека, нам нужно создать программное обеспечение, которое думает так же, как мы, и объясняет Почему, что что-то не удалось. В этом случае:
public static boolean isIntegerFromDecimalString(String possibleInteger) {
possibleInteger = possibleInteger.trim();
try {
// Integer parsing works great for "regular" integers like 42 or 13.
int num = Integer.parseInt(possibleInteger);
System.out.println("The possibleInteger = "+possibleInteger+" is a pure integer.");
return true;
} catch (NumberFormatException e) {
if (possibleInteger.equals(".")) {
System.out.println("The possibleInteger = " + possibleInteger + " is NOT an integer because it is only a decimal point.");
return false;
} else if (possibleInteger.startsWith(".") && possibleInteger.matches("\\.[0-9]*")) {
if (possibleInteger.matches("\\.[0]*")) {
System.out.println("The possibleInteger = " + possibleInteger + " is an integer because it starts with a decimal point and afterwards is all zeros.");
return true;
} else {
System.out.println("The possibleInteger = " + possibleInteger + " is NOT an integer because it starts with a decimal point and afterwards is not all zeros.");
return false;
}
} else if (possibleInteger.endsWith(".") && possibleInteger.matches("[0-9]*\\.")) {
System.out.println("The possibleInteger = "+possibleInteger+" is an impure integer (ends with decimal point).");
return true;
} else if (possibleInteger.contains(".")) {
String[] partsOfPossibleInteger = possibleInteger.split("\\.");
if (partsOfPossibleInteger.length == 2) {
//System.out.println("The possibleInteger = " + possibleInteger + " is split into '" + partsOfPossibleInteger[0] + "' and '" + partsOfPossibleInteger[1] + "'.");
if (partsOfPossibleInteger[0].matches("[0-9]*")) {
if (partsOfPossibleInteger[1].matches("[0]*")) {
System.out.println("The possibleInteger = "+possibleInteger+" is an impure integer (ends with all zeros after the decimal point).");
return true;
} else if (partsOfPossibleInteger[1].matches("[0-9]*")) {
System.out.println("The possibleInteger = " + possibleInteger + " is NOT an integer because it the numbers after the decimal point (" +
partsOfPossibleInteger[1] + ") are not all zeros.");
return false;
} else {
System.out.println("The possibleInteger = " + possibleInteger + " is NOT an integer because it the 'numbers' after the decimal point (" +
partsOfPossibleInteger[1] + ") are not all numeric digits.");
return false;
}
} else {
System.out.println("The possibleInteger = " + possibleInteger + " is NOT an integer because it the 'number' before the decimal point (" +
partsOfPossibleInteger[0] + ") is not a number.");
return false;
}
} else {
System.out.println("The possibleInteger = "+possibleInteger+" is NOT an integer because it has a strange number of decimal-period separated parts (" +
partsOfPossibleInteger.length + ").");
return false;
}
} // else
System.out.println("The possibleInteger='"+possibleInteger+"' is NOT an integer, even though it has no decimal point.");
return false;
}
}
Код теста:
String[] testData = {"0", "0.", "0.0", ".000", "2", "2.", "2.0", "2.0000", "3.14159", ".0001", ".", "$4.0", "3E24", "6.0221409e+23"};
int i = 0;
for (String possibleInteger : testData ) {
System.out.println("");
System.out.println(i + ". possibleInteger='" + possibleInteger +"' isIntegerFromDecimalString = " + isIntegerFromDecimalString(possibleInteger));
i++;
}
Я думаю, что ваше объяснение проливает свет на ситуации, о которых люди, честно говоря, не думали, и позволило бы создать гораздо более надежный код. Однако вы предполагаете, что мы используем точку (.) В качестве разделителя. Это не касается удобочитаемости вводимых данных, таких как: разделитель тысяч, бухгалтерские скобки, другое основание или использование арабских чисел. Также нет причин генерировать исключение в этом методе, поскольку мы знаем каждое состояние, в котором должна находиться эта строка, учитывая ее неизменное состояние, и мы собираемся быть хорошими программистами и изменять ссылку - дальнейшее чтение wiki.c2.com/?ExceptionPatterns
Дэвид - вы абсолютно правы; особенно о разделителе тысяч запятых (что важно для удобочитаемости). Для действительно общего решения нам нужно будет принять во внимание все предположения - хотя я вполне уверен, что не так много людей используют неарабские числа. :-)
Мне не нравится метод с регулярным выражением, потому что регулярное выражение не может проверять диапазоны (Integer.MIN_VALUE, Integer.MAX_VALUE).
Если вы в большинстве случаев ожидаете значение int, а не int - что-то необычное, то я предлагаю версию с Integer.valueOf или Integer.parseInt с перехватом NumberFormatException. Преимущество такого подхода - ваш код хорошо читается:
public static boolean isInt(String s) {
try {
Integer.parseInt(s);
return true;
} catch (NumberFormatException nfe) {
return false;
}
}
Если вам нужно проверить, является ли String целочисленным, и позаботиться о производительности, тогда лучшим способом будет использовать java jdk-реализацию Integer.parseInt, но немного измененную (заменив throw на return false):
Эта функция имеет хорошую производительность и гарантирует правильный результат:
public static boolean isInt(String s) {
int radix = 10;
if (s == null) {
return false;
}
if (radix < Character.MIN_RADIX) {
return false;
}
if (radix > Character.MAX_RADIX) {
return false;
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
return false;
if (len == 1) // Cannot have lone "+" or "-"
return false;
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++), radix);
if (digit < 0) {
return false;
}
if (result < multmin) {
return false;
}
result *= radix;
if (result < limit + digit) {
return false;
}
result -= digit;
}
} else {
return false;
}
return true;
}
Ты мог бы:
long.long достаточно мало, чтобы его можно было представить как int.(Предполагая, что вам по какой-то причине придется реализовать это самостоятельно: вам, вероятно, сначала следует взглянуть на com.google.common.primitives.Ints.tryParse(String) и посмотреть, достаточно ли он для ваших целей (как предлагается в другом ответе).)
// Credit to Rastislav Komara’s answer: https://stackoverflow.com/a/237895/1725151
private static final Pattern nonZero = Pattern.compile("^-?[1-9]\\d*$");
// See if `str` can be parsed as an `int` (does not trim)
// Strings like `0023` are rejected (leading zeros).
public static boolean parsableAsInt(@Nonnull String str) {
if (str.isEmpty()) {
return false;
}
if (str.equals("0")) {
return true;
}
if (canParseAsLong(str)) {
long value = Long.valueOf(str);
if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
return true;
}
}
return false;
}
private static boolean canParseAsLong(String str) {
final int intMaxLength = 11;
return str.length() <= intMaxLength && nonZero.matcher(str).matches();
}
Этот метод также можно преобразовать для возврата Optional<Integer>, чтобы вам не приходилось дважды анализировать строку в клиентском коде (один раз, чтобы проверить, возможно ли это, а второй раз сделать это «по-настоящему»). Например:
if (canParseAsLong(str)) {
long value = Long.valueOf(str);
if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
return Optional.of((int) value);
}
}
небольшое улучшение @Jonas K anwser, эта функция исключит один единственный оператор, такой как "*".
public boolean isInteger(String str) {
// null pointer
if (str == null) {
return false;
}
int len = str.length();
// empty string
if (len == 0) {
return false;
}
// one digit, cannot begin with 0
if (len == 1) {
char c = str.charAt(0);
if ((c < '1') || (c > '9')) {
return false;
}
}
for (int i = 0; i < len; i++) {
char c = str.charAt(i);
// check positive, negative sign
if (i == 0) {
if (c == '-' || c == '+') {
continue;
}
}
// check each character matches [0-9]
if ((c < '0') || (c > '9')) {
return false;
}
}
return true;
}
Мне недавно (сегодня) нужно было найти быстрый способ сделать это, и, конечно, я собирался использовать подход исключения для облегчения, когда обезьяна на плече (совесть) проснулась, поэтому она унесла меня в эту старую знакомую кроличью нору; никакие исключения не намного дороже, на самом деле иногда исключения быстрее (старые многопроцессорные системы AIX), но, несмотря на то, что это слишком элегантно, поэтому я сделал то, чего никогда не делал младший я, и, к моему удивлению, никто здесь тоже не делал (извиняюсь, если кто-то это сделал, и я пропустил я, честно говоря, не нашел): так что я думаю мы все упустили; взглянув на то, как это реализовано в JRE, да, они выдали исключение, но мы всегда можем пропустить эту часть.
Младший я из 10 лет назад чувствовал бы, что это ниже его, но опять же, он громкий хвастун с плохим темпераментом и комплексом бога, так что это есть.
Я помещаю это здесь на благо всех, кто придет сюда в будущем. Вот что я нашел:
public static int parseInt(String s, int radix) throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
несколько ответов здесь, в которых говорится, что нужно попробовать разобрать целое число и поймать NumberFormatException, но вы не должны этого делать.
Таким образом будет создан объект исключения и будет генерироваться трассировка стека каждый раз, когда вы его вызываете, и это не целое число.
Лучшим способом с Java 8 было бы использовать поток:
boolean isInteger = returnValue.chars().allMatch(Character::isDigit);
Для Котлин, isDigitsOnly()(Также для Java TextUtils.isDigitsOnly()) из String всегда возвращает false, перед ним стоит отрицательный знак, хотя остальная часть символа является только цифрой. Например -
/** For kotlin*/
var str = "-123"
str.isDigitsOnly() //Result will be false
/** For Java */
String str = "-123"
TextUtils.isDigitsOnly(str) //Result will be also false
Итак, я быстро исправил это -
var isDigit=str.matches("-?\\d+(\\.\\d+)?".toRegex())
/** Result will be true for now*/
Что вы думаете о RegExp для решения?