正则表达式:忽略组的顺序

时间:2015-08-29 14:42:47

标签: java regex

我有一段文字:

  

randomtext 1150,25 USD randomtext

和一个简单的正则表达式来提取不同货币的金额:

(((\d+)(,?\s?|.)(\d{1,2}))\s?(PLN|EUR|USD|CHF|GBP))

这给了我这些小组:

  1. 1150,25 USD
  2. 1150,25
  3. 1150
  4. 25
  5. USD
  6. 但是,数字和货币可能会交换其头寸:

      

    randomtext USD 1150,25 randomtext

      

    randomtext USD1150,25 randomtext

    在保持当前分组的同时,如何在不重复整个群组(AB | BA)的情况下提高我的正则表达式以满足该条件?

3 个答案:

答案 0 :(得分:5)

您可以使用这种模式:

String p = "\\b (?=[\\dPEUCG])  # to jump quickly at interesting positions       \n" +
           "(?=     # open a lookahead                                           \n" +
           "    (?> [\\d,]+ \\s* )? # perhaps the value is before                \n" +
           "    (?<currency> PLN|EUR|USD|CHF|GBP )  # capture the currency       \n" +
           "    (?:\\b|\\d) # a word boundary or a digit                         \n" +
           ")       # close the lookahead                                        \n" +
           "(?> [B-HLNPRSU]{3} \\s* )? (?<value> \\d+(?:,\\d+)? )                  ";

Pattern RegComp = Pattern.compile(p, Pattern.COMMENTS);

String s = "USD 1150,25 randomtext \n" +
           "Non works randomtext 1150,25 USD randomtext\n" +
           "Works randomtextUSD 1150,25 USD randomtext\n" +
           "Works randomtext USD 1150,25 randomtext\n" +
           "Works randomtext USD1150,25 randomtext\n" +
           "Non work randomtext 1150,25 USD randomtext";

Matcher m = RegComp.matcher(s);

while( m.find() ) {
    System.out.println(m.group("value") + " : " + m.group("currency"));
}

这个想法是在一个先行(即零宽度断言)中捕获货币。前瞻只是一个断言,不消耗字符,里面的子模式描述之前的最终值。所以货币的位置不会改变任何东西。 该值是在前瞻之外捕获的。

关于\\b (?=[\\dPEUCG]): 此子模式的目标是过滤字符串中不是以不同货币的数字或首字母开头的单词开头的位置,而不测试整个模式。

答案 1 :(得分:0)

它不是太优雅,但您也可以通过以下方式实现:

(?<!\d|\d,)(?=(?:[\d,]+\s)*(PLN|EUR|USD|CHF|GBP)(?:\s*[\d,]+\s)*)(?=(?:PLN|EUR|USD|CHF|GBP)*\s*((\d+)(,?\s?|.)(\d{1,2}))\s?(?:PLN|EUR|USD|CHF|GBP)*)[\d,\sPLNEURUSDCHFGB]+(?=\b\s)

DEMO

但是如果你不需要匹配这个部分(例如替换等),只需捕获字符串的相关部分,它应该足以使用:

(?<!\d|\d,)(?=(?:[\d,]+\s)*(PLN|EUR|USD|CHF|GBP)(?:\s*[\d,]+\s)*)(?=(?:PLN|EUR|USD|CHF|GBP)*\s*((\d+)(,?\s?|.)(\d{1,2}))\s?(?:PLN|EUR|USD|CHF|GBP)*)

DEMO

它用于有害的前瞻:

  • (?=(?:[\d,]+\s)*(PLN|EUR|USD|CHF|GBP)(?:\s*[\d,]+\s)*) - 货币 数字之前或之后,
  • (?=((?:PLN|EUR|USD|CHF|GBP)*\s*(\d+)(,?\s?|.)(\d{1,2})(?:\s*(?:PLN|EUR|USD|CHF|GBP))*))
  • 以货币开头或后跟的数字

Example in Java

答案 2 :(得分:0)

以编程方式构造正则表达式:

BigDecimal amount = null;
String currency = null;
String currencyRegex = "(PLN|EUR|USD|CHF|GBP)";
String amountRegex = "(\\d+)(?:,?\\s?|.)(\\d{1,2})";
Pattern currencyAmountPattern = Pattern.compile(
    currencyRegex + "\\s?" + amountRegex
    + "|"
    + amountRegex + "\\s?" + currencyRegex);
Matcher matcher = currencyAmountPattern.matcher(input);
if (matcher.find()) {
    if (matcher.group(1) != null) {
        currency = matcher.group(1);
        amount = new BigDecimal(matcher.group(2) + "." + matcher.group(3));
    } else {
        currency = matcher.group(6);
        amount = new BigDecimal(matcher.group(4) + "." + matcher.group(5));
    }
}