Java Dizesi - Bir dizenin harf değil, yalnızca rakam içerip içermediğine bakın


196

Benim uygulama boyunca yük bir dize var ve sayıları harfleri ve benzeri değişir. ifHarf veya sayı içerip içermediğini görmek için basit bir ifadem var , ancak bir şey düzgün çalışmıyor. İşte bir pasaj.

String text = "abc"; 
String number; 

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

textDeğişken harf içermesine rağmen, koşul olarak döner true. Ve işlemek için &&her iki koşul da olmalıdır true.number = text;

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

Çözüm:

Bu soruya bir yorum tarafından sağlanan aşağıdaki kodu kullanarak bunu başardı. Diğer tüm gönderiler de geçerlidir!

Ben işe yaradı ilk yorumdan geldi. Sağlanan tüm örnek kodlar da geçerli gibi görünse de!

String text = "abc"; 
String number; 

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

5
içeren girdi olarak bir normal ifade almaz. İkisinden birini kullanın ya matches("\\d{2,}")da bir Patternve ile deneyinMatcher
Guillaume Polet

Dizenin ondalık değeri veya yalnızca tamsayı değerleri olabilir mi?
pseudoramble

3
Neden text.length ()> 2'yi kontrol ediyorsunuz? Sebebi nedir?
Kod Tutkulu

1
@RedHatcc Pattern.matches("[a-zA-Z]+", text) == falsebasitleştirilebilir!Pattern.matches("[a-zA-Z]+", text)
SARose

2
Java akışı API boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));formu Max MalyshPost kullanarak .
Yash

Yanıtlar:


356

Numarayı metin olarak işleyecekseniz, değiştirin:

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

için:

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

Bunun yerine dize kontrol edilmesinden gelmez alfabetik karakterler içeren, emin içerdiği olmak için kontrol sadece sayısal değerler.

Sayısal değeri gerçekten kullanmak istiyorsanız, Integer.parseInt()veya Double.parseDouble()aşağıda açıklananları kullanın .


Bir yan not olarak, boole değerlerini trueveya ile karşılaştırmak genellikle kötü uygulama olarak kabul edilir false. Sadece if (condition)veya kullanın if (!condition).


25
Muhtemelen çapa eklemek istiyorsunuz (örneğin ^[0-9]+$) aksi takdirde abc123defbir sayı olarak kabul edilecektir.
ICR

10
Bunun gerekli olduğunu düşünmüyorum. matches()yalnızca başından sonuna tam bir eşleşme olduğunda true değerini döndürür.
Chthonic Projesi

4
"^ -? \ d + \.? \ d * $" tüm dizeyi karşılaştırır ve yalnızca geçerli bir sayı olduğunda (negatifler ve ondalıklar dahil) eşleşir. Örneğin, 1, 10, 1.0, -1, -1.0 vb. İle eşleşir. Ayrıca "1" de eşleşir. ancak bu genellikle yine de ayrıştırılabilir.

16
Aramaya gerek yok && (text.length() > 2). Her şey normal ifade deseninde kontrol edilebilir:if (text.matches("[0-9]{3,}")
ctomek

Tamsayı olmayan sayılar için virgül veya noktaya ne dersiniz?
nibbana


14

Ben böyle yapardım:

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

$Kısmi olarak, örneğin önlemek; 1B.


1
Ben ihtiyacım yok text.length() > 2ben sadece yerini böylece parçayı ^[0-9]*$tarafından ^[0-9]+$emin ben en az bir numarasına sahip olmak.
YB Neden

8

Performans açısından parseInt ve benzeri diğer çözümlerden çok daha kötüdür, çünkü en azından istisna yönetimi gerektirir.

Ben jmh testleri çalıştırmak ve kullanarak String üzerinden yineleme bulduk charAt dizi ve sınır karakterleri ile chars karşılaştırma karşılaştırarak sadece dizi içeriyorsa test etmek için en hızlı yoludur.

JMH testi

Testler Character.isDigitvs Pattern.matcher().matchesvs performans karşılaştırmakLong.parseLong char karakterlerini .

Bu yollar, ascii olmayan dizeler ve +/- işaretleri içeren dizeler için farklı sonuçlar üretebilir.

Testler Verim modunda çalışır ( daha büyük daha iyidir , 5 ısınma yineleme ve 5 test yineleme ile ) çalışır.

Sonuçlar

İlk test yükünden parseLongneredeyse 100 kat daha yavaş olduğunu unutmayın isDigit.

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

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

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

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

Test odası

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

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

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

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

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

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

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

23 Şub 2018 tarihinde güncellendi

  • İki örnek daha ekleyin - biri charAtekstra dizi oluşturmak yerine diğeri IntStreamkarakter kodlarını kullanmak için
  • Döngülü test senaryoları için rakamsız bulunursa anında mola ekleyin
  • Döngülü test senaryoları için boş dize için false döndür

23 Şub 2018 tarihinde güncellendi

  • Akış değerini kullanmadan karakter değerini karşılaştıran bir test örneği (en hızlı!) Ekleyin

1
Eğer toCharArray koduna bakarsanız, bir char dizisi tahsis ve chars kopyalama (bu pahalı olabilir düşünüyorum). Dizeyi bir index ve charAt kullanarak yinelerseniz, daha hızlı olur? Andy'nin çözümünü testlerinize ekleyebilseydiniz de ilginç olurdu: boolean isNum = text.chars (). AllMatch (c -> c> = 48 && c <= 57)
Aldo Canepa

8

Yalnızca ALPHABETS içerdiği dizeyi kontrol etmek için aşağıdaki kodu kullanın:

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

Yalnızca NUMBER içerdiği dizeyi kontrol etmek için aşağıdaki kodu kullanın:

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

Umarım bu birine yardımcı olur!


3

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


1
sihirli sayıları azaltmak için aşağıdaki gibi karşılaştırabilirsiniz:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix

2

Regex.Match kullanabilirsiniz

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

Veya örneğin daha büyük sayılar için Integer.parseInt(String)veya daha iyi sürümler kullanabilirsiniz Long.parseLong(String):

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

Ve sonra aşağıdakilerle test edin:

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

.matches ("^ \\ d + $")
CrandellWS

2

Bir dizede yalnızca sayı olup olmadığını kontrol etmek için aşağıdaki normal ifadeler kullanılabilir:

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

trueDize sayı içermiyorsa yukarıdaki her iki koşul da döndürülür . Açık false, dizede yalnızca sayılar vardır.


2

Apache Commons Lang , org.apache.commons.lang.StringUtils.isNumeric(CharSequence cs)a argümanı olarak alınan Stringve yalnızca sayısal karakterlerden (Latin olmayan komut dosyalarından gelen sayılar dahil) oluşup oluşmadığını kontrol eder. Bu yöntem geri dönerfalseBoşluk, eksi, artı gibi karakterler ve virgül ve nokta gibi ondalık ayırıcılar varsa .

Bu sınıfın diğer yöntemleri daha fazla sayısal denetime izin verir.


1
Bu bir normal ifadeden çok daha hızlı olmalıdır; İşte uygulama: public static boolean isNumeric(String str) { if (str == null) { return false; } else { int sz = str.length(); for(int i = 0; i < sz; ++i) { if (!Character.isDigit(str.charAt(i))) { return false; } } return true; } }
Leo 21

1

Sayıları almak için birçok tesis var StringJava'da s'den (veya tersi). Kendinizi bunun komplikasyonundan kurtarmak için regex kısmını atlamak isteyebilirsiniz.

Örneğin, sizin için neyin Double.parseDouble(String s)geri döndüğünü görebilirsiniz . Dizede NumberFormatExceptionuygun bir değer bulamazsa a atmalıdır. Bu tekniği öneririm çünkü aslında Stringsayısal bir tür olarak temsil edilen değeri kullanabilirsiniz .


5
Girişinizi test etmek için bir istisnayı kullanmak kötü bir fikir olabilir, istisnalar büyük bir yük oluşturur.
Ofir Luzon

1
@OfirLuzon İstisnaların, ortaya çıkması beklenen vakaları ele almanın harika bir yolu olmadığını kabul ediyorum. Ancak, daha fazla bağlam olmadan bir performans hitinin olup olmayacağını söylemek zor.
pseudoramble

1

İşte kodum, umarım bu size yardımcı olacaktır!

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

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

    return isDigit;
}

0

Bu kod zaten yazılmıştır. Regex eşleşmesi yapmaktan daha kötü olmayan (son derece) küçük performans isabetinin sakıncası yoksa Integer.parseInt () veya Double.parseDouble () kullanın . String (veya yalnızca sayılar ise o hemen anlatacağım bir olduğu uygun olarak, sayı). Rakam, hem uzun dizeleri işlemek gerekiyorsa BigInteger ve BigDecimal dizeleri kabul spor yapıcıları. Bunlardan herhangi biri sayı olmayan bir sayı geçirmeye çalışırsanız (bir tane seçtiğiniz integrale bağlı olarak integral veya ondalık) bir NumberFormatException oluşturur . Alternatif olarak, gereksinimlerinize bağlı olarak, String'deki karakterleri tekrarlayın ve Character.isDigit () öğesini kontrol edin.ve / veya Karakter . isLetter () .


0
import java.util.*;

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

        }
    }


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

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

                }
                else if (Character.isLetter())
                {

                }

0

Çalışma testi örneği

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

import org.apache.commons.lang3.StringUtils;

public class PaserNo {

    public static void main(String args[]) {

        String text = "gg";

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

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

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

Yine de kodunuz "1a" vb. Tarafından kesilebilir, bu nedenle istisnayı kontrol etmeniz gerekir

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

Hayır kontrol yöntemi dizedir ya da değil

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

0

Böyle tipik bir senaryoya herhangi bir istisna atma / taşıma dahil etmek kötü bir uygulamadır.

Bu nedenle bir parseInt () güzel değil ama regex bunun için zarif bir çözüm, ancak aşağıdakilerden özen:
-bölümleri
-negatif sayılar
-Ondalık ayırıcı contries farklılık olabilir ( '' mesela '' ya)
-bazen boşluk veya virgül gibi binlik bir ayırıcıya izin verilir, örneğin 12,324,1000,355

Başvurunuzdaki tüm gerekli durumları ele almak için dikkatli olmalısınız, ancak bu normal ifade tipik senaryoları (pozitif / negatif ve kesirli, nokta ile ayrılmış) kapsar: ^ [- +]? \ D *.? \ D + $
İçin test, regexr.com öneririz .


0

Adam Bodrogi'nin biraz değiştirilmiş versiyonu:

public class NumericStr {


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

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

    return false;
}
}

Bugün kullanmak zorunda kaldım bu yüzden değişikliklerimi yayınladım. Para birimini, binlerce virgül veya nokta gösterimini ve bazı doğrulamaları içerir. Diğer para birimi gösterimlerini (euro, cent) içermez, doğrulama virgülleri her üçüncü basamaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.