嵌套的regexp和替换

时间:2014-02-25 17:02:22

标签: java regex

我有类似<p0=v0 p1=v1 p2=v2 ....>的字符串,我希望将pXvX交换为<v0=p0 v1=p1 v2=p2 ....>,使用 regexps 。 我只希望交换<>中的对。

我写道:

Pattern pattern = Pattern.compile("<(\\w*)=(\\w*)>");
Matcher matcher = pattern.matcher("<p1=v1>");
System.out.println(matcher.replaceAll("$2=$1"));

但它仅适用于一对pX=vX 有人可以解释我如何编写适用于多对的regexp?

5 个答案:

答案 0 :(得分:2)

简单,使用群组:

String input = "<p0=v0 p1=v1 p2=v2>";
//                                   |group 1
//                                   ||matches "p" followed by one digit
//                                   ||      |... followed by "="
//                                   ||      ||group 2
//                                   ||      |||... followed by "v", followed by one digit
//                                   ||      |||          |replaces group 2 with group 1,
//                                   ||      |||          |re-writes "=" in the middle
System.out.println(input.replaceAll("(p[0-9])=(v[0-9])", "$2=$1"));

输出:

<v0=p0 v1=p1 v2=p2>

答案 1 :(得分:0)

要替换<>之间的所有内容(让我们称之为标记)是 - imho - 如果标记之外可能出现相同的模式,则无法实现。

相反,要立即替换所有内容,我会选择两个正则表达式:

String str = "<p1=v1 p2=v2> p3=v3 <p4=v4>";
Pattern insideTag = Pattern.compile("<(.+?)>");
Matcher m = insideTag.matcher(str);

while(m.find()) {
    str = str.replace(m.group(1), m.group(1).replaceAll("(\\w*)=(\\w*)", "$2=$1"));
}
System.out.println(str);

//prints: <v1=p1 v2=p2> p3=v3 <v4=p4>

匹配器抓取<>之间的所有内容,并且对于每个匹配,它将替换第一个捕获组的内容与原始字符串上的交换的内容,但前提是它匹配{{1}当然。

尝试

(\w*)=(\w*)

给出输出

<p1=v1 p2=v2 just some trash> p3=v3 <p4=v4>

答案 2 :(得分:0)

如果Java可以执行\G锚点,这将适用于unnested&lt;&gt;的< 查找:((?:(?!\A|<)\G|<)[^<>]*?)(\w+)=(\w+)(?=[^<>]*?>)
替换(全局):$1$3=$2

正则表达式解释

 (                     # (1 start)
      (?:
           (?! \A | < )
           \G                    # Start at last match
        |  
           <                     # Or, <
      )
      [^<>]*? 
 )                     # (1 end)
 ( \w+ )               # (2)
 =
 ( \w+ )               # (3)
 (?= [^<>]*? > )       # There must be a closing > ahead

Perl测试用例

$/ = undef;
$str = <DATA>;
$str =~ s/((?:(?!\A|<)\G|<)[^<>]*?)(\w+)=(\w+)(?=[^<>]*?>)/$1$3=$2/g;
print $str;
__DATA__
<p0=v0 p1=v1  p2=v2 ....>

输出&gt;&gt;

<v0=p0 v1=p1  v2=p2 ....>

答案 3 :(得分:0)

这应该适用于仅交换< and >

之间的对
String string = "<p0=v0 p1=v1 p2=v2> a=b c=d xyz=abc <foo=bar baz=bat>";
Pattern pattern1 = Pattern.compile("<[^>]+>");
Pattern pattern2 = Pattern.compile("(\\w+)=(\\w+)");
Matcher matcher1 = pattern1.matcher(string);
StringBuffer sbuf = new StringBuffer();
while (matcher1.find()) {
    Matcher matcher2 = pattern2.matcher(matcher1.group());
    matcher1.appendReplacement(sbuf, matcher2.replaceAll("$2=$1"));
}
matcher1.appendTail(sbuf);
System.out.println(sbuf);

输出:

<v0=p0 v1=p1 v2=p2> a=b c=d xyz=abc <bar=foo bat=baz>

答案 4 :(得分:0)

您可以使用此模式:

"((?:<|\\G(?<!\\A))\\s*)(p[0-9]+)(\\s*=\\s*)(v[0-9]+)"

为确保对在开角支架之后,模式以:

开头
(?:<|\\G(?<!\\A))

表示:最后一场比赛结束时的开场角括号OR

\\G是在最后一次匹配或字符串开头后立即定位的位置(换句话说,它是字符串中正则表达式引擎的最后一个位置,即零字符串的开头)。为了避免在字符串开头匹配,我添加了一个负面的lookbehind (?<!\\A) - &gt; 之前没有字符串的开头

这个技巧会强制每一对先于另一对或<

示例:

String subject = "p5=v5 <p0=v0 p1=v1 p2=v2 p3=v3> p4=v4";
String pattern = "((?:<|\\G(?<!\\A))\\s*)(p[0-9]+)(\\s*=\\s*)(v[0-9]+)";
String result = subject.replaceAll(pattern, "$1$4$3$2");

如果您需要 p v 具有相同的号码,您可以将其更改为:

String pattern = "((?:<|\\G(?<!\\A))\\s*)(p([0-9]+))(\\s*=\\s*)(v\\3)";
String result = subject.replaceAll(pattern, "$1$5$4$2");

如果尖括号之间的部分可以包含其他内容(不是成对):

String pattern = "((?:<|\\G(?<!\\A))(?:[^\s>]+\\s*)*?\\s*)(p([0-9]+))(\\s*=\\s*)(v\\3)";
String result = subject.replaceAll(pattern, "$1$4$3$2");

注意:所有这些模式仅检查是否有开角括号,但不检查是否有闭合角括号。如果缺少一个闭合括号,所有对都将被替换,直到两个第一个模式没有更多的连续对,直到下一个闭合角括号或第三个模式的字符串结尾。

您可以通过在每个模式的末尾添加(?=[^<>]*>)来检查是否存在结束尖括号。但是,添加此项将使您的模式完全无法执行。最好使用(?<=<)[^<>]++(?=>)在尖括号之间搜索部分,并在回调函数中执行对的替换。您可以查看this post来实现它。