首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >用于捕获和替换元素textContent的RegEx

用于捕获和替换元素textContent的RegEx
EN

Stack Overflow用户
提问于 2019-05-21 05:21:55
回答 1查看 178关注 0票数 -1

我想要替换这两个示例中"name“节点的值。我使用regex group来匹配并替换它。分组工作正常,但替换不起作用。

代码语言:javascript
复制
input 1
<xml
   <user:address>.../</user:address>
   <user:name>foo</user:name>
</xml>

input 2

<xml
   <user:address>.../</user:address>
   <street:name>bar</street:name>
</xml>


private static final String NAME_GROUP = "name";
public static final Pattern pattern = Pattern.compile("<.*:name>" + "(?<" + NAME + ">.*)</.*:name>");

final Matcher nameMatcher = pattern.matcher(str);
final String s = nameMatcher.find() ? nameMatcher.group(NAME_GROUP) : null;
System.out.println(s);

//foo
//bar

现在,当我替换掉

代码语言:javascript
复制
String output = nameMatcher.replaceFirst("hello")
 I get 
 hello</xml>

虽然我对以下内容有所期待

代码语言:javascript
复制
<xml
       <user:address>.../</user:address>
       <user:name>hello</user:name>
    </xml>

对于这两个示例。为什么组在工作,而不是替换?

EN

回答 1

Stack Overflow用户

发布于 2019-05-23 17:28:21

StringMatcher中的replaceFirst/replaceAll操作将始终替换整个匹配项。它们可以归结为如下的实现

代码语言:javascript
复制
public static String replace(
    CharSequence source, Pattern p, String replacement, boolean all) {

    Matcher m = p.matcher(source);
    if(!m.find()) return source.toString();
    StringBuffer sb = new StringBuffer();
    do m.appendReplacement(sb, replacement); while(all && m.find());
    return m.appendTail(sb).toString();
}

注意,在Java9之前,我们必须在这里使用StringBuffer而不是StringBuilder

当我们忽略在替换字符串中具有组引用的功能时,我们可以向下钻取更深一层的逻辑,并获得

代码语言:javascript
复制
public static String replaceLiteral(
    CharSequence source, Pattern p, String replacement, boolean all) {

    Matcher m = p.matcher(source);
    if(!m.find()) return source.toString();
    StringBuilder sb = new StringBuilder();
    int lastEnd = 0;
    do {
        sb.append(source, lastEnd, m.start()).append(replacement);
        lastEnd = m.end();
    } while(all && m.find());
    return sb.append(source, lastEnd, source.length()).toString();
}

对于这段代码,很容易更改逻辑来替换特定的命名组,而不是整个匹配:

代码语言:javascript
复制
public static String replaceGroupWithLiteral(
    CharSequence source, Pattern p, String groupName, String replacement, boolean all) {

    Matcher m = p.matcher(source);
    if(!m.find()) return source.toString();
    StringBuilder sb = new StringBuilder();
    int lastEnd = 0;
    do {
        sb.append(source, lastEnd, m.start(groupName)).append(replacement);
        lastEnd = m.end(groupName);
    } while(all && m.find());
    return sb.append(source, lastEnd, source.length()).toString();
}

这已经足够实现您的示例了:

代码语言:javascript
复制
private static final String NAME_GROUP = "name";
public static final Pattern pattern
    = Pattern.compile("<.*:name>" + "(?<" + NAME_GROUP + ">.*)</.*:name>");
代码语言:javascript
复制
String input =
    "<xml\n"
  + "   <user:address>.../</user:address>\n"
  + "   <user:name>foo</user:name>\n"
  + "</xml>\n";
String s = replaceGroupWithLiteral(input, pattern, NAME_GROUP, "hello", false);
System.out.println(s);
代码语言:javascript
复制
<xml
   <user:address>.../</user:address>
   <user:name>hello</user:name>
</xml>

不过,我可能会用像这样的东西

代码语言:javascript
复制
public static final Pattern pattern
    = Pattern.compile("<([^<>:]*?:name)>" + "(?<" + NAME_GROUP + ">.*)</\\1>");

如上所述(通过方法名称可以清楚地看出),这与普通的regex替换操作不同,因为它总是按字面意思插入替换。要获得与原型相同的行为,需要更复杂和效率更低的代码,所以我只在确实需要引用组时才使用它(或者语法被认为是合同中的替代语法)。

代码语言:javascript
复制
public static String replaceGroup(
    CharSequence source, Pattern p, String groupName, String replacement, boolean all) {

    Matcher m = p.matcher(source);
    if(!m.find()) return source.toString();
    StringBuffer sb = new StringBuffer();
    do {
        int s = m.start(), gs = m.start(groupName), e = m.end(), ge = m.end(groupName);
        String prefix = s == gs? "":
            Matcher.quoteReplacement(source.subSequence(s, gs).toString());
        String suffix = e == ge? "":
            Matcher.quoteReplacement(source.subSequence(ge, e).toString());
        m.appendReplacement(sb, prefix+replacement+suffix);
    } while(all && m.find());
    return m.appendTail(sb).toString();
}

有了这个,如果我们使用,例如

代码语言:javascript
复制
String s = replaceGroup(input, pattern, NAME_GROUP, "[[${"+NAME_GROUP+"}]]", false);

我们会得到

代码语言:javascript
复制
<xml
   <user:address>.../</user:address>
   <user:name>[[foo]]</user:name>
</xml>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56228346

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档