在小写的括号字母上排除标记

时间:2013-05-14 18:38:41

标签: java regex

一个字符串可以包含一对多括号的小写字母,如String content = "This is (a) nightmare";我想将字符串转换为"<centamp>This is </centamp>(a) <centamp>nightmare</centamp>";所以基本上在这个字符串周围添加centamp标记但是如果它在括号中有一个小写字母应该从标记中排除。

这是我到目前为止所尝试过的,但它没有达到预期的效果。字符串中可能没有多对括号,并且每个括号都应该从标记中排除它。

Pattern pattern = Pattern.compile("^(.*)?(\\([a-z]*\\))?(.*)?$", Pattern.MULTILINE);    
String content = "This is (a) nightmare";
System.out.println(content.matches("^(.*)?(\\([a-z]*\\))?(.*)?$"));
System.out.println(pattern.matcher(content).replaceAll("&lt;centamp&gt;$1$3&lt;/centamp&gt;$2"));

3 个答案:

答案 0 :(得分:2)

这可以在一个replaceAll中完成:

String outputString =
    inputString.replaceAll("(?s)\\G((?:\\([a-z]+\\))*+)((?:(?!\\([a-z]+\\)).)+)",
                           "$1<centamp>$2</centamp>");

它允许括号\\([a-z]+\\)中的小写英文字母字符非空序列。

特点:

  • 仅标记空白序列。
  • 空字符串周围没有标记。

说明:

  • \G断言匹配边界,即下一场比赛只能从最后一场比赛结束开始。它也可以匹配字符串的开头(当我们还没有找到任何匹配时)。

  • 正则表达式的每个匹配将包含以下序列:0个或更多连续\\([a-z]+\\)(允许之间没有空格),后跟至少1个不形成\\([a-z]+\\)序列的字符

    • 0或更多连续\\([a-z]+\\)以涵盖字符串不以\\([a-z]+\\)开头的情况,以及字符串不包含\\([a-z]+\\)的情况。

      在此部分的模式(?:\\([a-z]+\\))*+中 - 请注意+之后*使量词占有,换句话说,它不允许回溯。简单地说,就是优化。

    • 需要一个字符限制来防止添加包含空字符串的标记。

      在此部分的模式中(?:(?!\\([a-z]+\\)).)+ - 请注意,对于每个字符,我会在匹配\\([a-z]+\\)之前检查它是否是模式(?!\\([a-z]+\\)).的一部分。

  • (?s)标志会导致.匹配任何字符,包括新行。这将允许标记包含跨越多行的文本。

答案 1 :(得分:1)

你只需用&lt; / centamp&gt; $ 1&lt; centamp&gt;替换所有“([a-z])”的出现。然后前置&lt; centamp&gt;并附加&lt; / centamp&gt;

String content = "Test (a) test (b) (c)";
Pattern pattern = Pattern.compile("(\\([a-z]\\))");
Matcher matcher = pattern.matcher(content);
String result = "&lt;centamp&gt;" + matcher.replaceAll("&lt;/centamp&gt;$1&lt;centamp&gt;") + "&lt;/centamp&gt;";

注意我在浏览器中写了以上内容,因此可能存在语法错误。

编辑以下是最简单的RegEx的完整示例。

import java.util.*;
import java.lang.*;
import java.util.regex.*;
class Main
{
    public static void main (String[] args) throws java.lang.Exception
    {
        String content = "test (a) (b) and (c)";
        String result = "<centamp>" + 
            content.replaceAll("(\\([a-z]\\))", "</centamp>$1<centamp>") +
            "</centamp>";
        result = result.replaceAll("<centamp></centamp>", "");
        System.out.print(result);
    }
}

答案 2 :(得分:0)

这是另一种使用清洁正则表达式的解决方案。解决方案更长,但它可以更灵活地调整条件以添加标签。

这里的想法是匹配包含小写字符的括号(我们不想标记的部分),然后使用匹配中的索引来标识我们要在标记中包含的部分。

// Regex for the parenthesis containing only lowercase English
// alphabet characters
static Pattern REGEX_IN_PARENTHESIS = Pattern.compile("\\([a-z]+\\)");

private static String addTag(String str) {
    Matcher matcher = REGEX_IN_PARENTHESIS.matcher(str);
    StringBuilder sb = new StringBuilder();

    // Index that we have processed up to last append into StringBuilder
    int lastAppend = 0;

    while (matcher.find()) {
        String bracket = matcher.group();

        // The string from lastAppend to start of a match is the part
        // we want to tag
        // If you want to, you can easily add extra logic to process
        // the string
        if (lastAppend < matcher.start()) { // will not tag if empty string
            sb.append("<centamp>")
              .append(str, lastAppend, matcher.start())
              .append("</centamp>");
        }

        // Append the parenthesis with lowercase English alphabet as it is
        sb.append(bracket);

        lastAppend = matcher.end();
    }

    // The string from lastAppend to end of string (no more match)
    // is the part we want to tag
    if (lastAppend < str.length()) {
        sb.append("<centamp>")
          .append(str, lastAppend, str.length())
          .append("</centamp>");
    }

    return sb.toString();
}