如何使用正则表达式提取子字符串

493

我有一个包含两个单引号字符'的字符串。在两个单引号之间的是我想要的数据。

我如何编写正则表达式从以下文本中提取出"the data i want"?

mydata = "some string with 'the data i want' inside";
14个回答

719

如果你想获取单引号之间的部分,可以使用下面这个正则表达式和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));
}

结果:

我想要的数据

15
该死...我总是忘记非贪婪模式的修饰符 :( - Mihai Toader
45
当你期望出现多个情况时,将“if”替换为“while”。 - OneWorld
23
请注意,此代码示例需要调用matcher.find()方法才能正常工作。如果未调用此方法,则在调用matcher.group(1)时会导致“无匹配项”的异常。 - rexford
30
@mFontoura的group(0)将返回包含外层''的完整匹配。group(1)将返回位于''之间但不包括''本身的内容。 - tagy22
6
@Larry,这是一个晚回复,但在这种情况下,“?”是非贪婪修饰符,这意味着对于“this 'is' my 'data' with quotes”,它会尽早停止并返回“is”,而不是匹配尽可能多的字符并返回“is' my 'data”,这是默认行为。 - Timekiller
显示剩余5条评论

82

14
在考虑软件如何分发时,需要注意一下。如果像WebStart那样,仅仅为了使用一个功能而添加Apache Commons是不明智的,但也可能不是这种情况。 此外,Apache Commons还有很多其他用途。尽管了解正则表达式很好,但在使用它时必须小心谨慎。 正则表达式可能很难阅读、编写和调试。在某些情况下,使用它可能不是最佳解决方案。 - Beothorn
4
有时候 StringUtils 已经存在于代码中,这种情况下使用这个解决方案会更加简洁易懂。 - Gábor Nagy
9
这就像你购买一辆车只为了行驶5英里(当你每年只需要旅行一次时)。 - prayagupa
1
虽然子字符串查找特定的字符串或值,但正则表达式查找格式。它越来越动态化。如果您正在寻找模式而不是特定值,则需要使用正则表达式。 - burak

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

    }
}

3
System.out.println(matcher.group(0)); <--- 零起始索引 - nclord
6
"第0组(group(0))没有特殊含义,捕获组从索引group(1)开始(即答案中的group(1)是正确的)。捕获组从左到右按顺序编号,从1开始。第0组表示整个匹配模式。" - 来源:https://docs.oracle.com/javase/8/docs/api/java/util/regex/Matcher.html#group-int- - Apriori
2
请记住,matches() 尝试匹配整个字符串,因此如果您的模式开头和结尾没有 ".*",它将找不到任何内容。 - oneturkmen
+1(或者如果可以的话,+100)给“import”语句!不知道为什么有些人在写答案时会忽略这些。 - undefined

20

这可以用一个简单的一行命令来实现:

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

通过使匹配组可选,也能满足当引号不存在时返回空白的情况。

请参见演示


15

自Java 9版本开始

从这个版本开始,你可以使用一个新的方法Matcher::results,该方法不带参数并能够轻松返回Stream<MatchResult>,其中MatchResult表示匹配操作的结果,并提供读取匹配组等功能(此类从Java 1.5版本就已知)。

String string = "Some string with 'the data I want' inside and 'another data I want'.";

Pattern pattern = Pattern.compile("'(.*?)'");
pattern.matcher(string)
       .results()                       // Stream<MatchResult>
       .map(mr -> mr.group(1))          // Stream<String> - the 1st group of each result
       .forEach(System.out::println);   // print them out (or process in other way...)

上面的代码片段会导致以下结果:

the data I want
another data I want
最大的优点在于当有一个或多个结果可用时,易于使用,而不是繁琐的 if (matcher.find())while (matcher.find()) 检查和处理。

11

因为您还选择了Scala,所以这是一个无需正则表达式的解决方案,可以轻松处理多个带引号的字符串:

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
易读的解决方案,这就是人们喜爱Scala的原因 :) - prayagupa
3
在Java中,为什么不直接使用.split('\'').get(2)或类似的方式呢?如果你认为这是可读的解决方案,我想你可能需要做一次脑部扫描 - 对我来说,它看起来像有人试图进行代码高尔夫比赛。 - ArtOfWarfare

10
String dataIWant = mydata.replaceFirst(".*'(.*?)'.*", "$1");

2
你能解释一下你的答案吗?比如为什么要使用 replaceFirst?为什么是 $1 - Elikill58
@Elikill58 这实际上相当聪明。.*'匹配第一个'之前的所有内容,包括',而'.*匹配之后的所有内容。(.*?)是一个非贪婪地捕获两个引号之间的所有内容的组,我想。$1表示我们想要用正则表达式匹配到的内容(在这种情况下是所有内容)替换为第一个捕获组的内容((.*?)匹配两个引号之间的所有内容)。$0将意味着整个正则表达式。 - undefined

3

就像JavaScript中一样:

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

实际的正则表达式是:/'([^']+)'/

如果您使用非贪婪修饰符(如另一篇文章所述),则应该像这样:

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

它更加干净。


2

String dataIWant = mydata.split("'")[1];

请参考演示示例

这段代码的意思是从mydata字符串中获取单引号内的数据并将其存储在dataIWant变量中。

2

Apache Commons Lang提供了许多java.lang API的辅助工具,最主要的是字符串操作方法。 在您的情况下,起始和结束子字符串相同,因此只需调用以下函数。

StringUtils.substringBetween(String str, String tag)

Gets the String that is nested in between two instances of the same String.

如果起始和结束子字符串不同,则使用以下重载方法。
StringUtils.substringBetween(String str, String open, String close)

Gets the String that is nested in between two Strings.

如果您想要匹配所有子字符串的实例,则使用以下命令:
StringUtils.substringsBetween(String str, String open, String close)

Searches a String for substrings delimited by a start and end tag, returning all matching substrings in an array.

针对此示例,获取所有匹配子字符串的实例

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接