วิธีการแยกตัวเลขจากสตริงและรับอาร์เรย์ของ ints?


109

ฉันมีตัวแปร String (โดยทั่วไปคือประโยคภาษาอังกฤษที่มีจำนวนตัวเลขที่ไม่ระบุ) และฉันต้องการแยกตัวเลขทั้งหมดออกเป็นจำนวนเต็ม ฉันสงสัยว่ามีวิธีแก้ปัญหาอย่างรวดเร็วด้วยนิพจน์ทั่วไปหรือไม่?


ฉันใช้วิธีแก้ปัญหาของ Sean และเปลี่ยนแปลงเล็กน้อย:

LinkedList<String> numbers = new LinkedList<String>();

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(line); 
while (m.find()) {
   numbers.add(m.group());
}

1
ตัวเลขล้อมรอบด้วยช่องว่างหรืออักขระอื่น ๆ หรือไม่? ตัวเลขถูกจัดรูปแบบอย่างไรเป็นเลขฐานสิบหกฐานแปดไบนารีทศนิยมหรือไม่?
Buhake Sindi

ฉันคิดว่ามันชัดเจนจากคำถามนั่นคือประโยคภาษาอังกฤษที่มีตัวเลข ยิ่งไปกว่านั้นฉันกำลังพูดถึงอาร์เรย์จำนวนเต็มดังนั้นสิ่งที่ฉันกำลังมองหาคือจำนวนเต็ม
John Manak

คำตอบ:


175
Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There are more than -2 and less than 12 numbers here");
while (m.find()) {
  System.out.println(m.group());
}

... ภาพพิมพ์-2และ12.


-? จับคู่เครื่องหมายลบนำหน้า - สามารถเลือกได้ \ d ตรงกับหลักและเราจำเป็นต้องเขียน\เป็น\\ใน Java String แม้ว่า ดังนั้น \ d + จะจับคู่ 1 หลักขึ้นไป


4
คุณช่วยเติมเต็มคำตอบด้วยการอธิบายนิพจน์ทั่วไปของคุณได้ไหม
OscarRyz

3
-? จับคู่เครื่องหมายลบนำหน้า - สามารถเลือกได้ \ d จับคู่ตัวเลขและเราต้องเขียน \ as \\ ใน Java String ดังนั้น \\ d + จับคู่อีก 1 หลัก
Sean Owen

7
ฉันเปลี่ยนนิพจน์เป็น Pattern.compile ("-? [\\ d \\.] +") เพื่อรองรับการลอย คุณนำทางฉันไปทางนี้แน่นอน Thx!
jlengrand

วิธีการนี้จะตรวจสอบตัวเลข 2,000แต่ไม่ได้ตรวจสอบหมายเลขรูปแบบเช่น สำหรับการใช้งานดังกล่าว-?\\d+,?\\d+|-?\\d+
Mugoma J. Okomba

ที่รองรับเพียงจุลภาคเดียวดังนั้นจะพลาด "2,000,000" นอกจากนี้ยังยอมรับสตริงเช่น "2,00" หากต้องรองรับตัวคั่นด้วยลูกน้ำ: -?\\d+(,\\d{3})*ควรใช้งานได้
Sean Owen

52

สิ่งที่เกี่ยวกับการใช้replaceAllวิธี java.lang.String:

    String str = "qwerty-1qwerty-2 455 f0gfg 4";      
    str = str.replaceAll("[^-?0-9]+", " "); 
    System.out.println(Arrays.asList(str.trim().split(" ")));

เอาท์พุต:

[-1, -2, 455, 0, 4]

คำอธิบาย

[^-?0-9]+
  • [และ]คั่นชุดของอักขระที่จะจับคู่ครั้งเดียวกล่าวคือเพียงครั้งเดียวในลำดับใดก็ได้
  • ^ตัวระบุพิเศษที่ใช้ในตอนต้นของชุดใช้เพื่อระบุเพื่อจับคู่อักขระทั้งหมดที่ไม่มีอยู่ในชุดที่คั่นแทนอักขระทั้งหมดที่มีอยู่ในชุด
  • + ระหว่างหนึ่งครั้งและไม่ จำกัด จำนวนครั้งให้มากที่สุดเท่าที่จะเป็นไปได้โดยให้คืนเท่าที่จำเป็น
  • -? หนึ่งในอักขระ“ -” และ“?”
  • 0-9 อักขระที่อยู่ในช่วงระหว่าง“ 0” ถึง“ 9”

4
ทำไมคุณถึงต้องการเก็บเครื่องหมายคำถาม? นอกจากนี้ยังถือว่านี้-ด้วยตัวเองเป็นตัวเลขพร้อมกับสิ่งที่ชอบ9-, และ---6 1-2-3
Alan Moore

1
ทางเลือกที่ดีมากโดยไม่ต้องใช้การนำเข้าไลบรารี;)
Jcc.Sanabria

18
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(myString);
while (m.find()) {
    int n = Integer.parseInt(m.group());
    // append n to list
}
// convert list to array, etc

จริงๆแล้วคุณสามารถแทนที่ [0-9] ด้วย \ d ได้ แต่เกี่ยวข้องกับการเว้นวรรคแบ็กสแลชคู่ซึ่งทำให้อ่านยากขึ้น


อ๊ะ. ฌอนจัดการกับตัวเลขติดลบนั่นจึงเป็นการปรับปรุง
sidereal

2
ของคุณจะจัดการกับตัวเลขที่เป็นลบเช่นกันหากคุณใช้ "-? [0-9] +"
cegprakash

9
  StringBuffer sBuffer = new StringBuffer();
  Pattern p = Pattern.compile("[0-9]+.[0-9]*|[0-9]*.[0-9]+|[0-9]+");
  Matcher m = p.matcher(str);
  while (m.find()) {
    sBuffer.append(m.group());
  }
  return sBuffer.toString();

นี่คือการแยกตัวเลขที่คงทศนิยมไว้


ไม่จัดการเชิงลบ
OneCricketeer

5

คำตอบที่ยอมรับจะตรวจพบตัวเลข แต่ไม่พบตัวเลขที่จัดรูปแบบเช่น 2,000 หรือทศนิยมเช่น 4.8 สำหรับการใช้งานดังกล่าว-?\\d+(,\\d+)*?\\.?\\d+?:

        Pattern p = Pattern.compile("-?\\d+(,\\d+)*?\\.?\\d+?");
        List<String> numbers = new ArrayList<String>();
        Matcher m = p.matcher("Government has distributed 4.8 million textbooks to 2,000 schools");
        while (m.find()) {  
            numbers.add(m.group());
        }   
        System.out.println(numbers);

เอาท์พุต: [4.8, 2,000]


1
@JulienS: ฉันไม่เห็นด้วย regex นี้ทำมากกว่าที่ OP ขอและทำไม่ถูกต้อง (อย่างน้อยที่สุดส่วนทศนิยมควรอยู่ในกลุ่มที่เป็นทางเลือกโดยมีทุกสิ่งที่จำเป็นและโลภ: (?:\.\d+)?.)
อลันมัวร์

แน่นอนคุณมีจุดสำหรับส่วนทศนิยม อย่างไรก็ตามเป็นเรื่องปกติมากที่จะพบตัวเลขที่จัดรูปแบบ
Julien

@AlanMoore ผู้เยี่ยมชม SO จำนวนมากกำลังมองหาวิธีใด ๆ / ที่แตกต่างกันในการแก้ไขปัญหาเกี่ยวกับความเหมือน / ความแตกต่างที่แตกต่างกันและจะเป็นประโยชน์หากมีการนำเสนอข้อเสนอแนะ แม้แต่ OP ก็อาจมีขนาดใหญ่เกินไป
Mugoma J. Okomba

4

สำหรับจำนวนตรรกยะให้ใช้อันนี้: (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))


1
OP กล่าวว่าจำนวนเต็มไม่ใช่จำนวนจริง นอกจากนี้คุณลืมที่จะหลบหนีจุดและไม่จำเป็นต้องใช้วงเล็บเหล่านี้
Alan Moore

3

เมื่อใช้ Java 8 คุณสามารถทำได้:

String str = "There 0 are 1 some -2-34 -numbers 567 here 890 .";
int[] ints = Arrays.stream(str.replaceAll("-", " -").split("[^-\\d]+"))
                 .filter(s -> !s.matches("-?"))
                 .mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

หากคุณไม่มีตัวเลขติดลบคุณสามารถกำจัดreplaceAll(และใช้!s.isEmpty()ในfilter) ได้เพราะนั่นเป็นเพียงการแยกบางสิ่งอย่างถูกต้องเท่านั้น2-34(สามารถจัดการได้อย่างหมดจดด้วย regex in splitแต่มันค่อนข้างซับซ้อน)

Arrays.streamเปลี่ยนเราString[]ให้เป็นStream<String>.

filterกำจัดสตริงว่างที่นำหน้าและต่อท้ายรวมทั้งสตริง-ที่ไม่ได้เป็นส่วนหนึ่งของตัวเลข

mapToInt(Integer::parseInt).toArray()เรียกร้องให้parseIntแต่ละคนStringมอบint[]ไฟล์.


หรืออีกวิธีหนึ่ง Java 9 มีเมธอดMatcher.resultsซึ่งควรอนุญาตสำหรับบางสิ่งเช่น:

Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There 0 are 1 some -2-34 -numbers 567 here 890 .");
int[] ints = m.results().map(MatchResults::group).mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

ตามที่กล่าวมาสิ่งเหล่านี้ไม่ได้เป็นการปรับปรุงที่ยิ่งใหญ่กว่าการวนซ้ำผลลัพธ์ด้วยPattern/ Matcherตามที่แสดงในคำตอบอื่น ๆ แต่ควรจะง่ายกว่านี้หากคุณต้องการติดตามสิ่งนี้ด้วยการดำเนินการที่ซับซ้อนมากขึ้นซึ่งจะง่ายขึ้นอย่างมากเมื่อใช้ สตรีม


1

แยกจำนวนจริงทั้งหมดโดยใช้สิ่งนี้

public static ArrayList<Double> extractNumbersInOrder(String str){

    str+='a';
    double[] returnArray = new double[]{};

    ArrayList<Double> list = new ArrayList<Double>();
    String singleNum="";
    Boolean numStarted;
    for(char c:str.toCharArray()){

        if(isNumber(c)){
            singleNum+=c;

        } else {
            if(!singleNum.equals("")){  //number ended
                list.add(Double.valueOf(singleNum));
                System.out.println(singleNum);
                singleNum="";
            }
        }
    }

    return list;
}


public static boolean isNumber(char c){
    if(Character.isDigit(c)||c=='-'||c=='+'||c=='.'){
        return true;
    } else {
        return false;
    }
}

1

อักขระเศษส่วนและการจัดกลุ่มเพื่อแสดงจำนวนจริงอาจแตกต่างกันระหว่างภาษา จำนวนจริงเดียวกันสามารถเขียนได้หลายวิธีขึ้นอยู่กับภาษา

จำนวนสองล้านคนในภาษาเยอรมัน

2,000,000.00

และเป็นภาษาอังกฤษ

2.000.000,00

วิธีการดึงจำนวนจริงจากสตริงที่กำหนดด้วยวิธีที่ไม่เชื่อเรื่องพระเจ้า:

public List<BigDecimal> extractDecimals(final String s, final char fraction, final char grouping) {
    List<BigDecimal> decimals = new ArrayList<BigDecimal>();
    //Remove grouping character for easier regexp extraction
    StringBuilder noGrouping = new StringBuilder();
    int i = 0;
    while(i >= 0 && i < s.length()) {
        char c = s.charAt(i);
        if(c == grouping) {
            int prev = i-1, next = i+1;
            boolean isValidGroupingChar =
                    prev >= 0 && Character.isDigit(s.charAt(prev)) &&
                    next < s.length() && Character.isDigit(s.charAt(next));                 
            if(!isValidGroupingChar)
                noGrouping.append(c);
            i++;
        } else {
            noGrouping.append(c);
            i++;
        }
    }
    //the '.' character has to be escaped in regular expressions
    String fractionRegex = fraction == POINT ? "\\." : String.valueOf(fraction);
    Pattern p = Pattern.compile("-?(\\d+" + fractionRegex + "\\d+|\\d+)");
    Matcher m = p.matcher(noGrouping);
    while (m.find()) {
        String match = m.group().replace(COMMA, POINT);
        decimals.add(new BigDecimal(match));
    }
    return decimals;
}

1

หากคุณต้องการยกเว้นตัวเลขที่อยู่ในคำเช่น bar1 หรือ aa1bb ให้เพิ่มขอบเขตของคำลงในคำตอบตามนิพจน์ทั่วไป ตัวอย่างเช่น:

Pattern p = Pattern.compile("\\b-?\\d+\\b");
Matcher m = p.matcher("9There 9are more9 th9an -2 and less than 12 numbers here9");
while (m.find()) {
  System.out.println(m.group());
}

แสดง:

2
12

1

ฉันขอแนะนำให้ตรวจสอบค่า ASCII เพื่อแยกตัวเลขจากสตริงสมมติว่าคุณมีสตริงอินพุตเป็น myname12345และหากคุณต้องการแยกตัวเลข 12345คุณสามารถทำได้โดยการแปลง String เป็นCharacter Arrayก่อนจากนั้นใช้pseudocodeต่อไปนี้

    for(int i=0; i < CharacterArray.length; i++)
    {
        if( a[i] >=48 && a[i] <= 58)
            System.out.print(a[i]);
    }

เมื่อแยกตัวเลขแล้วให้ผนวกเข้ากับอาร์เรย์

หวังว่านี่จะช่วยได้


สตริง Java นับเป็นลำดับของหน่วยรหัส Unicode / UTF-16 โดยการออกแบบ UTF-16 อักขระ 128 ตัวแรกจะมีค่าเท่ากัน (โดยไม่ใช่ขนาดเดียวกัน) กับการเข้ารหัส ASCII นอกเหนือจากนั้นการคิดว่าคุณกำลังจัดการกับ ASCII จะนำไปสู่ข้อผิดพลาด
ทอม Blodget


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