วิธีการแยกซับสตริงโดยใช้ regex


382

ฉันมีสตริงที่มีสองคำพูดเดียวในนั้น'ตัวละคร ในระหว่างเครื่องหมายคำพูดเดี่ยวคือข้อมูลที่ฉันต้องการ

ฉันจะเขียน regex เพื่อแยก "ข้อมูลที่ฉันต้องการ" จากข้อความต่อไปนี้ได้อย่างไร

mydata = "some string with 'the data i want' inside";

คำตอบ:


569

สมมติว่าคุณต้องการส่วนระหว่างคำพูดเดียวใช้นิพจน์ปกตินี้ด้วยMatcher:

"'(.*?)'"

ตัวอย่าง:

String mydata = "some string with 'the data i want' inside";
Pattern pattern = Pattern.compile("'(.*?)'");
Matcher matcher = pattern.matcher(mydata);
if (matcher.find())
{
    System.out.println(matcher.group(1));
}

ผลลัพธ์:

ข้อมูลที่ฉันต้องการ

12
ประณาม .. ฉันมักจะลืมเกี่ยวกับตัวดัดแปลงที่ไม่ใช่โลภ :(
Mihai Toader

33
แทนที่ "ถ้า" ด้วย "ในขณะที่" เมื่อคุณคาดว่าจะมีเหตุการณ์มากกว่าหนึ่งเกิดขึ้น
OneWorld

14
โปรดทราบว่า matcher.find () เป็นสิ่งจำเป็นสำหรับตัวอย่างโค้ดนี้ให้ใช้งานได้ การไม่เรียกวิธีนี้จะส่งผลให้เกิดข้อยกเว้น "ไม่พบที่ตรงกัน" เมื่อมีการเรียกชื่อ matcher.group (1)
rexford

25
@mFontoura กลุ่ม (0) จะคืนค่าการจับคู่ทั้งหมดด้วย '' ด้านนอก กลุ่ม (1) ส่งคืนสิ่งที่อยู่ในระหว่าง '' โดยไม่มี '' ตัวเอง
tagy22

6
@ Larry นี่คือการตอบกลับช้า แต่? ในกรณีนี้คือตัวดัดแปลงที่ไม่โลภเพื่อที่this 'is' my 'data' with quotesมันจะหยุด แต่เนิ่น ๆ และกลับมาisแทนที่จะจับคู่ตัวละครให้ได้มากที่สุดและกลับมาis' my 'dataซึ่งเป็นพฤติกรรมเริ่มต้น
Timekiller

68

คุณไม่ต้องการ regex สำหรับสิ่งนี้

เพิ่ม apache คอมมอนส์ lang ลงในโครงการของคุณ ( http://commons.apache.org/proper/commons-lang/ ) จากนั้นใช้:

String dataYouWant = StringUtils.substringBetween(mydata, "'");

12
คุณต้องคำนึงถึงว่าซอฟต์แวร์ของคุณจะเผยแพร่อย่างไร ถ้ามันเป็นเหมือน webstart คุณไม่ควรเพิ่ม Apache Commons เพื่อใช้ฟังก์ชันนี้ แต่อาจจะไม่ใช่ นอกจาก Apache คอมมอนส์ยังมีข้อเสนออีกมากมาย แม้จะเป็นเรื่องยากที่จะรู้ว่า regex คุณจะต้องระมัดระวังในการใช้งาน Regex อาจอ่านเขียนและดีบักได้ยาก เมื่อพิจารณาบริบทที่ใช้สิ่งนี้อาจเป็นทางออกที่ดีกว่า
Beothorn

3
บางครั้ง StringUtils มีอยู่แล้วในกรณีเหล่านี้โซลูชันนี้สะอาดและอ่านได้มาก
Gábor Nagy

7
มันเหมือนกับการซื้อรถยนต์เพื่อเดินทาง 5 ไมล์ (เมื่อคุณเดินทางเพียงครั้งเดียวในหนึ่งปี)
prayagupd

ในขณะที่สตริงย่อยค้นหาสตริงหรือค่าเฉพาะ regex ค้นหารูปแบบ มันมีพลวัตมากขึ้นเรื่อย ๆ คุณต้อง regex หากคุณกำลังมองหารูปแบบแทนค่าพิเศษ
burakhan alkan

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

public class Test {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile(".*'([^']*)'.*");
        String mydata = "some string with 'the data i want' inside";

        Matcher matcher = pattern.matcher(mydata);
        if(matcher.matches()) {
            System.out.println(matcher.group(1));
        }

    }
}

2
System.out.println (matcher.group (0)); <--- ดัชนีจากศูนย์
nclord

4
ไม่กลุ่ม (0) มีความหมายพิเศษการจับภาพกลุ่มเริ่มต้นที่กลุ่มดัชนี (1) (เช่นกลุ่ม (1) ถูกต้องในคำตอบ) "กลุ่มการจับภาพถูกทำดัชนีจากซ้ายไปขวาเริ่มต้นที่หนึ่งกลุ่มศูนย์แสดงถึงรูปแบบทั้งหมด" - แหล่งที่มา: docs.oracle.com/javase/8/docs/api/java/util/regex/
Apriori

12

มีหนึ่งซับง่าย ๆ สำหรับสิ่งนี้:

String target = myData.replaceAll("[^']*(?:'(.*?)')?.*", "$1");

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

ดูการสาธิตสด


10

เนื่องจากคุณได้เลือกให้ Scala โซลูชันที่ไม่มี regex ซึ่งสามารถจัดการกับสตริงที่ยกมาหลาย ๆ ตัวได้อย่างง่ายดาย:

val text = "some string with 'the data i want' inside 'and even more data'"
text.split("'").zipWithIndex.filter(_._2 % 2 != 0).map(_._1)

res: Array[java.lang.String] = Array(the data i want, and even more data)

4
วิธีแก้ปัญหาที่อ่านได้ดังนั้นนั่นเป็นเหตุผลว่าทำไมผู้คนถึงรักสกาล่าฉันเชื่อ :)
prayagupd

3
ทำไมไม่เพียงแค่.split('\'').get(2)บางสิ่งใน Java? ฉันคิดว่าคุณอาจจำเป็นต้องได้รับการสแกนสมองหากคุณคิดว่านั่นเป็นวิธีแก้ปัญหาที่อ่านได้ - ดูเหมือนว่ามีคนพยายามทำกอล์ฟรหัสให้ฉัน
ArtOfWarfare


4

เช่นเดียวกับในจาวาสคริปต์:

mydata.match(/'([^']+)'/)[1]

regexp ที่แท้จริงคือ: /'([^']+)'/

หากคุณใช้ตัวแก้ไขที่ไม่ใช่โลภ (ตามโพสต์อื่น) มันเป็นเช่นนี้:

mydata.match(/'(.*?)'/)[1]

มันสะอาดกว่า


2

ในสกาลา

val ticks = "'([^']*)'".r

ticks findFirstIn mydata match {
    case Some(ticks(inside)) => println(inside)
    case _ => println("nothing")
}

for (ticks(inside) <- ticks findAllIn mydata) println(inside) // multiple matches

val Some(ticks(inside)) = ticks findFirstIn mydata // may throw exception

val ticks = ".*'([^']*)'.*".r    
val ticks(inside) = mydata // safe, shorter, only gets the first set of ticks


1

Apache Commons Lang มีโฮสต์ของตัวช่วยอรรถประโยชน์สำหรับ java.lang API ซึ่งเป็นวิธีการจัดการสตริงที่สะดุดตาที่สุด ในกรณีของคุณสตริงย่อยเริ่มต้นและสิ้นสุดเหมือนกันดังนั้นเพียงเรียกใช้ฟังก์ชันต่อไปนี้

StringUtils.substringBetween(String str, String tag)

Gets String ที่ซ้อนกันในระหว่างสองกรณีของสายเดียวกัน

หากสตริงย่อยเริ่มต้นและสิ้นสุดแตกต่างกันให้ใช้วิธีโอเวอร์โหลดต่อไปนี้

StringUtils.substringBetween(String str, String open, String close)

รับค่าสตริงที่ซ้อนระหว่างสองสตริง

หากคุณต้องการอินสแตนซ์ทั้งหมดของสตริงย่อยที่ตรงกันให้ใช้

StringUtils.substringsBetween(String str, String open, String close)

ค้นหาสตริงสำหรับสตริงคั่นด้วยเริ่มต้นและสิ้นสุดแท็ก กลับสตริงที่ตรงกันทั้งหมดในอาร์เรย์

สำหรับตัวอย่างที่เป็นปัญหาจะได้รับอินสแตนซ์ทั้งหมดของสตริงย่อยที่ตรงกัน

String[] results = StringUtils.substringsBetween(mydata, "'", "'");

0

คุณสามารถใช้สิ่งนี้ฉันใช้ในขณะที่วงเพื่อเก็บซับสตริงการแข่งขันทั้งหมดในอาร์เรย์ถ้าคุณใช้

if (matcher.find()) { System.out.println(matcher.group(1)); }

คุณจะได้ซับสตริงการจับคู่เพื่อให้คุณสามารถใช้สิ่งนี้เพื่อรับซับสตริงการแข่งขันทั้งหมด

Matcher m = Pattern.compile("[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+").matcher(text);
   // Matcher  mat = pattern.matcher(text);
    ArrayList<String>matchesEmail = new ArrayList<>();
        while (m.find()){
            String s = m.group();
            if(!matchesEmail.contains(s))
                matchesEmail.add(s);
        }

    Log.d(TAG, "emails: "+matchesEmail);

0

เพิ่มapache.commonsพึ่งพาpom.xmlของคุณ

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.3.2</version>
</dependency>

และรหัสด้านล่างทำงาน

StringUtils.substringBetween(String mydata, String "'", String "'")

0

บางวิธีที่กลุ่ม (1) ไม่ได้ผลสำหรับฉัน ฉันใช้กลุ่ม (0) เพื่อค้นหารุ่น url

Pattern urlVersionPattern = Pattern.compile("\\/v[0-9][a-z]{0,1}\\/");
Matcher m = urlVersionPattern.matcher(url);
if (m.find()) { 
    return StringUtils.substringBetween(m.group(0), "/", "/");
}
return "v0";
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.