具有优先级的Java正则表达式匹配模式

时间:2016-06-21 02:02:59

标签: java regex

我正在使用一个系统,其中&后跟一个字母或数字代表一种颜色 有效字符可以跟随&是[A-Fa-fK-Ok-or0-9]

例如,我有字符串&aThis is a test &bstring that &ehas plenty &4&lof &7colors.

我希望在每个& x 中拆分,同时将& x 保留在字符串中。
所以我在我的正则表达中使用了积极的前瞻 (?=(&[A-Fa-fK-Ok-or0-9]))
这完全没问题,输出是:

&aThis is a test 
&bstring that 
&ehas plenty 
&4
&lof 
&7colors.

问题是,两个& x 的实例彼此相邻的地点不应该被拆分,而该行应该是&4&lof

有谁知道我可以使用什么样的正则表达式,以便当两个& x 彼此相邻时它们匹配在一起。颜色代码的两个实例应优先于单个实例。

3 个答案:

答案 0 :(得分:1)

问题描述

问题是已知的:您需要标记一个字符串,该字符串可能包含您需要在结果字符串列表/数组中作为单个项目保留的连续分隔符。

使用环视分割无法帮助,因为 无固定的环视会测试字符串中的每个位置。如果您的模式匹配字符串中的任何字符,则可以使用\G运算符,但情况并非如此。 因此,甚至添加了+量词 - s0.split("(?=(?:&[A-Fa-fK-Ok-or0-9])+)" would still return &4, &lof as separate tokens

解决方案

使用匹配而不是拆分,并使用构建块来保持其可读性。

String s0 = "This is a text&aThis is a test &bstring that &ehas plenty &4&lof &7colors.";
String colorRx = "&[A-Fa-fK-Ok-or0-9]";
String nonColorRx = "[^&]*(?:&(?![A-Fa-fK-Ok-or0-9])[^&]*)*";
Pattern pattern = Pattern.compile("(?:" + colorRx + ")+" + nonColorRx + "|" + nonColorRx);
Matcher m = pattern.matcher(s0);
List<String> res = new ArrayList<>();
while (m.find()){
    if (!m.group(0).isEmpty()) res.add(m.group(0)); // Add if non-empty!
} 
System.out.println(res); 
// => [This is a text, &aThis is a test , &bstring that , &ehas plenty , &4&lof , &7colors.]

正则表达式是

(?:&[A-Fa-fK-Ok-or0-9])+[^&]*(?:&(?![A-Fa-fK-Ok-or0-9])[^&]*)*|[^&]*(?:&(?![A-Fa-fK-Ok-or0-9])[^&]*)*

请参阅regex demo here。它实际上是基于您的初始模式:首先,我们匹配所有颜色代码(1个或多个序列),然后我们匹配不是颜色序列起点的0+个字符(即除颜色代码之外的所有字符串) )。 [^&]*(?:&(?![A-Fa-fK-Ok-or0-9])[^&]*)*子模式是(?s)(?:(?!&[A-Fa-fK-Ok-or0-9]).)*的同义词,当您需要匹配除指定文本之外的一些文本块时,它非常方便,但由于它占用资源(特别是在Java中),展开版本更可取。

因此,模式 - (?:" + colorRx + ")+" + nonColorRx + "|" + nonColorRx - 匹配1 + colorRx个子模式,后跟可选的nonColorRx子模式,OR(|)零个或多个nonColorRx个子模式。 .group(0).isEmpy()不允许在结果数组中使用空字符串。

答案 1 :(得分:0)

我试过了:

{

      String line = "&aThis is a test &bstring that &ehas plenty &4&lof &7colors.";
      String pattern = " &(a-z)*(0-9)*";

      String strs[] = line.split(pattern, 0);
      for (int i=0; i<strs.length; i++){
          if (i!=0){
              System.out.println("&"+strs[i]);
          } else {
              System.out.println(strs[i]);
          }
      }

}

,输出为: {

&aThis is a test
&bstring that
&ehas plenty
&4&lof
&7colors.

}

我们可以添加&amp;在所有子串的开头,以获得您正在寻找的结果。

答案 2 :(得分:0)

这样的事情会起作用。

它使用String#split方法并将有效行放入ArrayList(例如colorLines

String mainStr = "&aThis is a test &bstring that &ehas plenty &4&lof &7colors";
String [] arr = mainStr.split("&");

List<String> colorLines = new ArrayList<String>();

String lastColor = "";
for (String s : arr)
{
    s = s.trim();
    if (s.length() > 0)
    {
        if (s.length() == 1)
        {
            lastColor += s;
        }
        else
        {
            colorLines.add(lastColor.length() > 0 ? lastColor + s : s);
            lastColor = "";
        }
    }
}

for (String s : colorLines)
{
    System.out.println(s);
}

<强>输出

aThis is a test
bstring that
ehas plenty
4lof
7colors