ใช้ Java เพื่อค้นหาสตริงย่อยของสตริงที่ใหญ่กว่าโดยใช้ Regular Expression


141

ถ้าฉันมีสตริงแบบนี้:

FOO[BAR]

ฉันต้องการวิธีทั่วไปในการดึงสตริง "BAR" ออกจากสตริงเพื่อไม่ว่าสตริงใดที่อยู่ระหว่างวงเล็บเหลี่ยมก็จะสามารถรับสตริงได้

เช่น

FOO[DOG] = DOG
FOO[CAT] = CAT

คำตอบ:


257

คุณควรจะสามารถใช้ตัวระบุปริมาณที่ไม่โลภโดยเฉพาะ *? คุณอาจต้องการสิ่งต่อไปนี้:

Pattern MY_PATTERN = Pattern.compile("\\[(.*?)\\]");

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

ในการแยกสตริงคุณสามารถใช้สิ่งต่อไปนี้:

Matcher m = MY_PATTERN.matcher("FOO[BAR]");
while (m.find()) {
    String s = m.group(1);
    // s now contains "BAR"
}

16
เป็นมูลค่าการกล่าวขวัญว่าหากมีการขึ้นบรรทัดใหม่ระหว่างวงเล็บเหลี่ยมสิ่งนี้จะล้มเหลวและคุณควรใช้แฟล็ก Pattern.DOTALL เพื่อหลีกเลี่ยงสิ่งนั้น
cletus

เมื่อใช้รูปแบบด้านบนแล้วคุณจะใช้สิ่งนั้นเพื่อแยกสตริงที่มีสตริง BAR ได้อย่างไร? ฉันกำลังดู Pattern API และ Matcher API แต่ฉันยังไม่แน่ใจว่าจะรับสตริงได้อย่างไร
digiarnie

@cletus: โทรดี! @digiarnie: ฉันได้เพิ่มการแก้ไขคำตอบที่มีรหัสฟางผู้ชายสำหรับการจับคู่
Bryan Kyle

30

วิธีที่ไม่ใช่ regex:

String input = "FOO[BAR]", extracted;
extracted = input.substring(input.indexOf("["),input.indexOf("]"));

หรือเพื่อประสิทธิภาพ / การใช้งานหน่วยความจำที่ดีขึ้นเล็กน้อย (ขอบคุณ Hosam):

String input = "FOO[BAR]", extracted;
extracted = input.substring(input.indexOf('['),input.lastIndexOf(']'));

1
ฉันจะใช้lastIndexOf(']')แทนซึ่งจะจัดการกับวงเล็บที่ซ้อนกัน นอกจากนี้ฉันเชื่อว่าการใช้ไฟล์indexOf(char)จะเร็วกว่าindexOf(String).
Hosam Aly

ยินดีต้อนรับ หมายเหตุของคุณเกี่ยวกับประสิทธิภาพก็มีความเกี่ยวข้องมากเช่นกันเนื่องจากlastIndexOfจะเร็วกว่าในการค้นหาวงเล็บปิด
Hosam Aly

3
อะไรที่เร็วกว่า indexof substring etc etc หรือ regexp?
ทศกัณฐ์

2
ดูค่า Amit สำหรับ "สกัด" ด้านล่าง: input.indexOf ('[') + 1
gcbound

28

นี่คือตัวอย่างการทำงาน:

RegexpExample.java

package org.regexp.replace;

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

public class RegexpExample
{
    public static void main(String[] args)
    {
        String string = "var1[value1], var2[value2], var3[value3]";
        Pattern pattern = Pattern.compile("(\\[)(.*?)(\\])");
        Matcher matcher = pattern.matcher(string);

        List<String> listMatches = new ArrayList<String>();

        while(matcher.find())
        {
            listMatches.add(matcher.group(2));
        }

        for(String s : listMatches)
        {
            System.out.println(s);
        }
    }
}

จะแสดง:

value1
value2
value3

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

public static String get_match(String s, String p) {
    // returns first match of p in s for first group in regular expression 
    Matcher m = Pattern.compile(p).matcher(s);
    return m.find() ? m.group(1) : "";
}

get_match("FOO[BAR]", "\\[(.*?)\\]")  // returns "BAR"

public static List<String> get_matches(String s, String p) {
    // returns all matches of p in s for first group in regular expression 
    List<String> matches = new ArrayList<String>();
    Matcher m = Pattern.compile(p).matcher(s);
    while(m.find()) {
        matches.add(m.group(1));
    }
    return matches;
}

get_matches("FOO[BAR] FOO[CAT]", "\\[(.*?)\\]")) // returns [BAR, CAT]

5

หากคุณต้องการรับสิ่งที่อยู่ระหว่าง[]คุณสามารถใช้\[([^\]]*)\]ดังนี้:

Pattern regex = Pattern.compile("\\[([^\\]]*)\\]");
Matcher m = regex.matcher(str);
if (m.find()) {
    result = m.group();
}

หากคุณต้องการให้อยู่ในรูปแบบidentifier + [ + content + ]คุณสามารถ จำกัด การแยกเนื้อหาได้ก็ต่อเมื่อตัวระบุเป็นตัวเลขและตัวอักษร:

[a-zA-Z][a-z-A-Z0-9_]*\s*\[([^\]]*)\]

สิ่งนี้จะตรวจสอบสิ่งต่างๆเช่นFoo [Bar]หรือmyDevice_123["input"]ตัวอย่างเช่น

ปัญหาหลัก

ปัญหาหลักคือเมื่อคุณต้องการแยกเนื้อหาของสิ่งนี้:

FOO[BAR[CAT[123]]+DOG[FOO]]

Regex จะไม่ทำงานและจะกลับมาและBAR[CAT[123 ถ้าเราเปลี่ยน Regex เป็นแสดงว่าเราก็โอเค แต่ถ้าคุณพยายามดึงเนื้อหาจากสิ่งที่ซับซ้อนกว่านี้เช่น:FOO
\[(.*)\]

FOO[BAR[CAT[123]]+DOG[FOO]] = myOtherFoo[BAR[5]]

Regexes จะไม่ทำงาน

Regex ที่ถูกต้องที่สุดในการดึงเนื้อหาที่เหมาะสมในทุกกรณีจะซับซ้อนกว่ามากเนื่องจากจะต้องสร้างสมดุลระหว่าง[]คู่และให้เนื้อหาแก่คุณ

วิธีแก้ปัญหาที่ง่ายกว่า

หากปัญหาของคุณเริ่มซับซ้อนและมีเนื้อหา[]ตามอำเภอใจคุณสามารถปรับสมดุลคู่ของ[]และแยกสตริงโดยใช้รหัสเก่าธรรมดาแทน Regex:

int i;
int brackets = 0;
string c;
result = "";
for (i = input.indexOf("["); i < str.length; i++) {
    c = str.substring(i, i + 1);
    if (c == '[') {
        brackets++;
    } else if (c == ']') {
        brackets--;
        if (brackets <= 0) 
            break;
    }
    result = result + c;
}   

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


2

ฉันคิดว่าการแสดงออกปกติของคุณจะมีลักษณะดังนี้:

/FOO\[(.+)\]/

สมมติว่า FOO จะคงที่

ดังนั้นหากต้องการใส่สิ่งนี้ใน Java:

Pattern p = Pattern.compile("FOO\\[(.+)\\]");
Matcher m = p.matcher(inputLine);

FOO [BAR] FOO [BAZ] -> ด้วย regex ของคุณจะส่งคืน: "BAR] FOO [BAZ"
Mohammad Jafar Mashhadi

1
String input = "FOO[BAR]";
String result = input.substring(input.indexOf("[")+1,input.lastIndexOf("]"));

สิ่งนี้จะคืนค่าระหว่าง "[" ครั้งแรกและครั้งสุดท้าย "]"

Foo [Bar] => บาร์

Foo [Bar [test]] => บาร์ [ทดสอบ]

หมายเหตุ: คุณควรเพิ่มข้อผิดพลาดในการตรวจสอบว่าสตริงอินพุตไม่ถูกต้องหรือไม่


0

สมมติว่าไม่อนุญาตให้ใช้วงเล็บเหลี่ยมปิดอื่น ๆ ภายใน / FOO \ [([^ \]] *) \] /


0

ฉันต้องการกำหนดที่ฉันต้องการจำนวนสูงสุดของตัวละครที่ไม่ใช่] ระหว่างและ[ ]สิ่งเหล่านี้จำเป็นต้องหลีกเลี่ยงด้วยแบ็กสแลช (และใน Java จำเป็นต้องใช้ Escape อีกครั้ง) และคำจำกัดความของ non-] คือคลาสอักขระดังนั้นภายใน[และ](เช่น[^\\]]) ผลลัพธ์:

FOO\\[([^\\]]+)\\]

0

วิธีนี้ใช้งานได้หากคุณต้องการแยกวิเคราะห์สตริงซึ่งมาจาก mYearInDB.toString () = [2013] มันจะให้ 2013

Matcher n = MY_PATTERN.matcher("FOO[BAR]"+mYearInDB.toString());
while (n.find()) {
 extracredYear  = n.group(1);
 // s now contains "BAR"
    }
    System.out.println("Extrated output is : "+extracredYear);

0

regexp นี้ใช้ได้กับฉัน:

form\[([^']*?)\]

ตัวอย่าง:

form[company_details][0][name]
form[company_details][0][common_names][1][title]

เอาต์พุต:

Match 1
1.  company_details
Match 2
1.  company_details

ทดสอบบนhttp://rubular.com/


0
"FOO[DOG]".replaceAll("^.*?\\[|\\].*", "");

สิ่งนี้จะส่งคืนสตริงที่รับเฉพาะสตริงที่อยู่ในวงเล็บเหลี่ยม

สิ่งนี้จะลบสตริงทั้งหมดที่อยู่ภายนอกออกจากวงเล็บเหลี่ยม

คุณสามารถทดสอบโค้ดตัวอย่าง java นี้ทางออนไลน์: http://tpcg.io/wZoFu0

คุณสามารถทดสอบ regex ได้จากที่นี่: https://regex101.com/r/oUAzsS/1

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