如何在运行时生成正则表达式以匹配数值范围

时间:2011-06-14 19:45:50

标签: java regex

我需要在运行时生成一个与一系列数值匹配的正则表达式。

例如:在运行时,我可能会发现我需要一个正则表达式,匹配“范围”a-261-b.somethinga-543-b.something中的所有文件。

我需要生成一个匹配所有这些文件的正则表达式。有什么想法吗?

我需要用Java编写,所以如果有人知道任何特定于Java的方法,那么它也是可以接受的。

谢谢!

3 个答案:

答案 0 :(得分:13)

正则表达式是否适合此任务是值得商榷的。大多数人可能会争辩说不是。

但据我所知,你没有选择,因为你正在使用的API将正则表达式作为参数,所以这里...

代码

public class NumericRangeRegexGenerator {

    private static String baseRange(String num, boolean up, boolean leading1) {

        char c = num.charAt(0);
        char low  = up ? c : leading1 ? '1' : '0';
        char high = up ? '9' : c;

        if (num.length() == 1)
            return charClass(low, high);

        String re = c + "(" + baseRange(num.substring(1), up, false) + ")";

        if (up) low++; else high--;

        if (low <= high)
            re += "|" + charClass(low, high) + nDigits(num.length() - 1);

        return re;
    }

    private static String charClass(char b, char e) {
        return String.format(b==e ? "%c" : e-b>1 ? "[%c-%c]" : "[%c%c]", b, e);
    }

    private static String nDigits(int n) {
        return nDigits(n, n);
    }

    private static String nDigits(int n, int m) {
        return "[0-9]" + String.format(n==m ? n==1 ? "":"{%d}":"{%d,%d}", n, m);
    }

    private static String eqLengths(String from, String to) {

        char fc = from.charAt(0), tc = to.charAt(0);

        if (from.length() == 1 && to.length() == 1)
            return charClass(fc, tc);

        if (fc == tc)
            return fc + "("+rangeRegex(from.substring(1), to.substring(1))+")";

        String re = fc + "(" + baseRange(from.substring(1), true, false) + ")|"
                  + tc + "(" + baseRange(to.substring(1),  false, false) + ")";

        if (++fc <= --tc)
            re += "|" + charClass(fc, tc) + nDigits(from.length() - 1);

        return re;
    }    

    private static String nonEqLengths(String from, String to) {
        String re = baseRange(from,true,false) + "|" + baseRange(to,false,true);
        if (to.length() - from.length() > 1)
            re += "|[1-9]" + nDigits(from.length(), to.length() - 2);
        return re;
    }

    public static String rangeRegex(int n, int m) {
        return rangeRegex("" + n, "" + m);
    }

    public static String rangeRegex(String n, String m) {
        return n.length() == m.length() ? eqLengths(n, m) : nonEqLengths(n, m);
    }

}

用法

// Generate expression for range 123 - 321
String regexp = NumericRangeRegexGenerator.rangeRegex(123, 321);


说明

代码的简要说明如下。

形状上的范围0000 - abcdabcd - 9999

首先我们注意到0000 - abcd等匹配范围非常简单。

例如000 - 527的表达式可以表示为

  • [0-4]后跟两个任意数字,或
  • 5后跟00 - 27(递归解析!)

形状1000 - abcdabcd - 9999的范围同样简单。

下限,不同长度的上限。

如果“from” - 数字比“to”数字短,则相当直接。

假设例如from - 数字有3位数,to - 数字有7位数。然后表达式可以如下组成:

  • from - 999(如上所述),
  • 任意456位数:[1-9][0-9]{3-5}
  • 1000000 - to(如上所述)

相等长度的下限/上限。

这是最棘手的情况(但仍然不是 虽然棘手!)

再一次,最好通过一个例子来描述解决方案。考虑范围273 - 548。表达式可以由以下部分组成:

  • 2后跟73 - 99(后面描述的部分),
  • [34]后跟任意两位数字,或
  • 5后跟00 - 48(后面描述的部分)

答案 1 :(得分:1)

让我看看我是否正确理解这一点。您有一个名为a-NUMBER-b.txt的文件。您需要检查号码是否正确。这是如何完成的:

要检查数字,请假设格式正确:

String name = getName();
int myInt = Integer.parseInt(name.split(a + "-")[1].split("-" + b + ".txt")[0]);

检查格式:

name.startsWith(a + "-") && name.endWith("-" + b + ".txt")

如果我回答正确,请告诉我 莱恩

答案 2 :(得分:0)

这样的事情可能有用,但不确定拆分的成本。

File[] files = new File("foo").listFiles();
for( int i = 0; i < files.length; i++ )
{
    String fn = files[i].getName();
    String sl[] = fn.split( "-" );
    int num = Integer.parseInt( sl[1] );

    if( num >= min && num <= max )
         //do stuff
}