Java String - ดูว่าสตริงมีตัวเลขเท่านั้นไม่ใช่ตัวอักษรหรือไม่


196

ฉันมีสตริงที่ฉันโหลดตลอดทั้งแอปพลิเคชันของฉันและมันเปลี่ยนจากตัวเลขเป็นตัวอักษรและเช่นนั้น ฉันมีifคำสั่งง่ายๆเพื่อดูว่ามันมีตัวอักษรหรือตัวเลข แต่มีบางสิ่งบางอย่างที่ทำงานไม่ถูกต้อง นี่คือตัวอย่าง

String text = "abc"; 
String number; 

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

แม้ว่าตัวแปรไม่ประกอบด้วยตัวอักษรเงื่อนไขผลตอบแทนที่เป็นtext trueและ&&ควรประเมินผลตามเงื่อนไขทั้งสองอย่างที่จะต้องtrueดำเนินการnumber = text;

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

สารละลาย:

ฉันสามารถแก้ไขปัญหานี้ได้โดยใช้รหัสต่อไปนี้ที่ได้รับจากความคิดเห็นในคำถามนี้ โพสต์อื่น ๆ ทั้งหมดมีผลเช่นกัน!

สิ่งที่ฉันใช้ที่ทำงานมาจากความคิดเห็นแรก แม้ว่ารหัสตัวอย่างที่ให้มาทั้งหมดดูเหมือนจะใช้ได้เช่นกัน!

String text = "abc"; 
String number; 

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

5
บรรจุไม่ได้ใช้ regexp เป็นอินพุต ใช้อย่างใดอย่างหนึ่งmatches("\\d{2,}")หรือลองกับPatternและMatcher
Guillaume Polet

สตริงสามารถมีค่าทศนิยมหรือค่าจำนวนเต็มเท่านั้นได้หรือไม่
pseudoramble

3
ทำไมคุณตรวจสอบข้อความ text ()> 2? เหตุผลคืออะไร
รหัสกระตือรือร้น

1
@RedHatcc Pattern.matches("[a-zA-Z]+", text) == falseสามารถทำให้ง่ายขึ้น!Pattern.matches("[a-zA-Z]+", text)
SARose

2
การใช้boolean isNumeric = someString.chars().allMatch(x -> Character.isDigit(x));แบบฟอร์มJava สตรีมมิ่ง API Max Malyshโพสต์
Yash

คำตอบ:


356

หากคุณกำลังประมวลผลหมายเลขเป็นข้อความให้เปลี่ยน:

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

ถึง:

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

แทนที่จะตรวจสอบว่าสตริงไม่อักขระที่เป็นตัวอักษรให้ตรวจสอบให้แน่ใจว่ามีตัวเลขเท่านั้น

หากคุณต้องการใช้ค่าตัวเลขให้ใช้ Integer.parseInt()หรือDouble.parseDouble()ตามที่คนอื่นได้อธิบายไว้ด้านล่าง


ตามบันทึกข้างก็โดยทั่วไปถือว่าปฏิบัติไม่ดีในการเปรียบเทียบค่าบูลีนไปหรือtrue falseเพียงแค่ใช้หรือif (condition)if (!condition)


25
คุณอาจต้องการเพิ่มจุดยึด (เช่น^[0-9]+$) มิฉะนั้นabc123defจะถือว่าเป็นตัวเลข
ICR

10
ฉันไม่คิดว่ามันจำเป็น matches()ผลตอบแทนจริงถ้าหากมันเป็นการจับคู่ที่สมบูรณ์ตั้งแต่ต้นจนจบ
โครงการ Chthonic

4
"^ -? \ d + \.? \ d * $" จะเปรียบเทียบสตริงทั้งหมดและจับคู่ก็ต่อเมื่อมันเป็นตัวเลขที่ถูกต้อง (รวมถึงเนกาทีฟและทศนิยม) ตัวอย่างเช่นมันจะตรงกับ 1, 10, 1.0, -1, -1.0 เป็นต้นและจะตรงกับ "1" แต่นั่นก็มักจะสามารถแยกวิเคราะห์ได้

16
&& (text.length() > 2)ไม่จำเป็นต้องโทรไม่เป็น ทุกอย่างสามารถตรวจสอบได้ในรูปแบบ regex:if (text.matches("[0-9]{3,}")
ctomek

เครื่องหมายจุลภาคหรือจุดสำหรับตัวเลขที่ไม่ใช่จำนวนเต็มคืออะไร
นิพพาน

20

คุณยังสามารถใช้NumberUtil.isCreatable (String str)จาก Apache Commons


4
ฉันคิดว่าไม่NumberUtil.isCreatable(String str)ถูกต้องที่จะใช้สำหรับสิ่งที่คำถามเดิมถาม เช่นNumberUtil.isCreatable( "09" )ผลตอบแทนfalseแม้มีตัวเลขเท่านั้น"09"
Abdull

14

นี่คือวิธีที่ฉันจะทำ:

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

$จะหลีกเลี่ยงเช่นการแข่งขันบางส่วน; 1B.


1
ฉันไม่ต้องการชิ้นtext.length() > 2ส่วนดังนั้นฉันจึงแทนที่^[0-9]*$ด้วย^[0-9]+$เพื่อให้แน่ใจว่าฉันมีตัวเลขอย่างน้อยหนึ่งตัว
YB สาเหตุที่

8

ผลการดำเนินงานที่ชาญฉลาด parseIntและช่างเลวร้ายยิ่งกว่าโซลูชันอื่น ๆ เพราะอย่างน้อยต้องมีการจัดการข้อยกเว้น

ฉันรันการทดสอบ jmh และพบว่าการวนซ้ำสตริงโดยใช้ charAtและการเปรียบเทียบ chars กับ chars ที่ขอบเขตเป็นวิธีที่เร็วที่สุดในการทดสอบว่าสตริงมีเฉพาะตัวเลขหรือไม่

การทดสอบ JMH

การทดสอบเปรียบเทียบประสิทธิภาพของCharacter.isDigitvs Pattern.matcher().matchesvsLong.parseLong vs การตรวจสอบค่าถ่าน

วิธีเหล่านี้สามารถสร้างผลลัพธ์ที่แตกต่างกันสำหรับสตริงและสตริงที่มีเครื่องหมาย +/-

การทดสอบทำงานในโหมดกำลังการผลิต ( ดีกว่าดีกว่า ) ด้วยการวอร์มอัพ 5 ครั้งและการทดสอบซ้ำ 5 ครั้ง

ผล

โปรดทราบว่าparseLongช้ากว่าisDigitการทดสอบครั้งแรกเกือบ 100 เท่า

## 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

ชุดทดสอบ

@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 กุมภาพันธ์ 2018

  • เพิ่มอีกสองกรณี - กรณีหนึ่งใช้charAtแทนการสร้างอาร์เรย์พิเศษและอีกกรณีใช้IntStreamรหัสถ่าน
  • เพิ่มตัวแบ่งทันทีหากพบตัวเลขที่ไม่ใช่ตัวเลขสำหรับกรณีทดสอบแบบลูป
  • ส่งคืน false สำหรับสตริงว่างสำหรับกรณีทดสอบที่วนลูป

อัปเดตเมื่อวันที่ 23 กุมภาพันธ์ 2018

  • เพิ่มอีกหนึ่งกรณีทดสอบ (เร็วที่สุด!) ที่เปรียบเทียบค่าถ่านโดยไม่ต้องใช้สตรีม

1
หากคุณดูที่รหัสของ toCharArray มันจะทำการจัดสรรอาร์เรย์และคัดลอกอักขระ (ฉันคิดว่าอาจมีราคาแพง) ถ้าคุณทำซ้ำสตริงโดยใช้ดรรชนีและ charAt มันจะเร็วขึ้นไหม จะน่าสนใจเช่นกันหากคุณสามารถเพิ่มโซลูชันจาก Andy ในการทดสอบของคุณ: บูลีน isNum = text.chars (). allMatch (c -> c> = 48 && c <= 57)
อัลโด Canepa

8

ในการตรวจสอบสตริงที่มีเพียง ALPHABETS เท่านั้นให้ใช้รหัสต่อไปนี้:

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

ในการตรวจสอบสตริงที่มีเพียง NUMBER ใช้รหัสต่อไปนี้:

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

หวังว่าสิ่งนี้จะช่วยให้ใครบางคน!


3

บูลีน isNum = text.chars (). allMatch (c -> c> = 48 && c <= 57)


1
เพื่อลดจำนวนเวทมนตร์คุณสามารถเปรียบเทียบดังนี้:boolean isNum = text.chars().allMatch(c -> c >= '0' && c <= '9')
Phe0nix

2

คุณสามารถใช้ Regex.Match

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

หรือคุณสามารถใช้การกลับด้านเช่นInteger.parseInt(String)หรือดีกว่าLong.parseLong(String)สำหรับจำนวนที่มากขึ้นเช่น:

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

จากนั้นทดสอบด้วย:

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

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

2

regexs ด้านล่างสามารถใช้เพื่อตรวจสอบว่าสตริงมีตัวเลขหรือไม่เท่านั้น:

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

เงื่อนไขทั้งสองข้างต้นจะส่งคืนtrueหากสตริงมีตัวเลขที่ไม่ใช่ บนfalseสตริงมีตัวเลขเท่านั้น


2

Apache Commons Langจัดเตรียมorg.apache.commons.lang.StringUtils.isNumeric(CharSequence cs)ซึ่งใช้เป็นอาร์กิวเมนต์ a Stringและตรวจสอบว่าประกอบด้วยอักขระที่เป็นตัวเลขล้วนๆหรือไม่ (รวมถึงตัวเลขจากสคริปต์ที่ไม่ใช่ภาษาละติน) เมธอดนั้นจะคืนค่าfalseหากมีอักขระเช่นช่องว่างเครื่องหมายบวกและตัวคั่นทศนิยมเช่นเครื่องหมายจุลภาคและจุด

วิธีอื่นของคลาสนั้นอนุญาตให้มีการตรวจสอบตัวเลขเพิ่มเติม


1
นี่ควรจะเร็วกว่า regex มาก นี่คือการดำเนินการ: 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

1

มีสิ่งอำนวยความสะดวกมากมายในการรับตัวเลขจากStrings ใน Java (และในทางกลับกัน) คุณอาจต้องการข้ามส่วน regex เพื่อรักษาความยุ่งยากของตัวเอง

ตัวอย่างเช่นคุณสามารถลองและดูว่าDouble.parseDouble(String s)ผลตอบแทนอะไรสำหรับคุณ มันควรโยนNumberFormatExceptionถ้ามันไม่พบค่าที่เหมาะสมในสตริง ฉันจะแนะนำเทคนิคนี้เพราะคุณสามารถใช้ประโยชน์จากค่าที่แสดงโดยStringเป็นชนิดตัวเลข


5
การใช้ข้อยกเว้นเป็นสาเหตุในการทดสอบอินพุตของคุณอาจเป็นแนวคิดที่ไม่ดีข้อยกเว้นสร้างค่าใช้จ่ายจำนวนมาก
Ofir Luzon

1
@OfirLuzon ฉันยอมรับว่าข้อยกเว้นไม่ใช่วิธีที่ดีในการจัดการกับกรณีที่คาดว่าจะเกิดขึ้น อย่างไรก็ตามฉันคิดว่าเป็นการยากที่จะบอกได้ว่าจะมีการแสดงที่มีประสิทธิภาพหรือไม่
pseudoramble

1

นี่คือรหัสของฉันหวังว่านี่จะช่วยคุณได้!

 public boolean isDigitOnly(String text){

    boolean isDigit = false;

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

    return isDigit;
}

0

รหัสนี้เขียนแล้ว หากคุณไม่ทราบ (มาก) ประสิทธิภาพการทำงานเล็ก ๆ น้อย ๆ ตี - ซึ่งอาจจะไม่เลวร้ายยิ่งกว่าการทำการแข่งขัน regex - ใช้Integer.parseInt ()หรือDouble.parseDouble () ที่จะบอกคุณทันทีถ้าสตริงเป็นตัวเลขเท่านั้น (หรือเป็นตัวเลขตามความเหมาะสม) หากคุณต้องการจัดการกับสตริงจำนวนที่ยาวขึ้นทั้งตัวสร้างกีฬาBigIntegerและBigDecimalที่ยอมรับ Strings สิ่งเหล่านี้จะทำให้NumberFormatException เกิดขึ้นถ้าคุณพยายามส่งผ่านตัวเลขที่ไม่ใช่จำนวนเต็ม (อินทิกรัลหรือทศนิยมตามที่คุณเลือกแน่นอน) อีกทางหนึ่งขึ้นอยู่กับความต้องการของคุณเพียงแค่วนอักขระในสตริงและตรวจสอบCharacter.isDigit ()และ / หรือCharacter.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

ตัวอย่างการทดสอบการทำงาน

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();
    }
}

ยังคงรหัสของคุณสามารถแบ่งโดย "1a" ฯลฯ ดังนั้นคุณต้องตรวจสอบข้อยกเว้น

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());
                }
            }

วิธีการตรวจสอบ no เป็น string หรือไม่

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

0

มันเป็นวิธีปฏิบัติที่ไม่ดีที่จะเกี่ยวข้องกับข้อยกเว้นการขว้างปา / จัดการกับสถานการณ์ทั่วไป

ดังนั้น parseInt () จึงไม่ดี แต่ regex เป็นคำตอบที่สวยงามสำหรับสิ่งนี้ แต่ดูแลสิ่งต่อไปนี้:
-fractions -negative
numbers
-degimal separator อาจแตกต่างใน contries (เช่น ',' หรือ '.')
-sometimes มันได้รับอนุญาตให้มีตัวคั่นพันที่เรียกว่าเช่นช่องว่างหรือเครื่องหมายจุลภาคเช่น 12,324,1000.355

เพื่อจัดการกรณีที่จำเป็นทั้งหมดในใบสมัครของคุณคุณต้องระวัง แต่ regex นี้ครอบคลุมสถานการณ์ทั่วไป (บวก / ลบและเศษส่วนคั่นด้วยจุด): ^ [- +]? \ d *.? dd $ $
สำหรับ การทดสอบผมขอแนะนำให้regexr.com


0

Adam Bodrogi เวอร์ชั่นดัดแปลงเล็กน้อย:

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;
}
}

ต้องใช้สิ่งนี้ในวันนี้ดังนั้นเพียงโพสต์การแก้ไขของฉัน รวมถึงสกุลเงินเครื่องหมายจุลภาคหลายพันหรือเครื่องหมายระยะเวลาและการตรวจสอบบางอย่าง ไม่รวมเครื่องหมายสกุลเงินอื่น ๆ (ยูโรเซ็นต์) เครื่องหมายจุลภาคการตรวจสอบเป็นตัวเลขสามหลักทุกตัว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.