我有类似<p0=v0 p1=v1 p2=v2 ....>
的字符串,我希望将pX
与vX
交换为<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?
答案 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来实现它。