Вопрос о том, подходят ли регулярные выражения для этой задачи, спорен. Большинство людей, вероятно, утверждают, что это не так.
Однако, насколько я понимаю, у вас нет выбора, поскольку используемый вами 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);
1011 *
*
Объяснение
Ниже приведено краткое объяснение кода.
Диапазоны в форме 0000
- abcd
и abcd
- 9999
Сначала отметим, что сопоставить диапазоны, такие как 0000
- abcd
, довольно просто.
Выражение, например 000
- 527
, может быть выражено как
[0-4]
, за которыми следуют две произвольные цифры или
5
, за которыми следует 00
- 27
(что разрешается рекурсивно!)
Диапазоны на фигуре 1000
- abcd
и abcd
- 9999
такие же простые.
Нижний предел, верхний предел различной длины.
Если номер "from" короче номера "to", то он довольно прямой.
Предположим, например, что номер from
имеет 3 цифры, а номер to
имеет 7 цифр. Выражение может быть составлено следующим образом:
from
- 999
(как описано выше),
- Любой
4
, 5
или 6
значный номер: [1-9][0-9]{3-5}
или
1000000
- to
(как описано выше)
Нижний предел / верхний предел равной длины.
Это самая сложная ситуация (но не , хотя хитрая!)
Решение, опять же, лучше всего описано на примере. Рассмотрим диапазон 273
- 548
. Выражение может быть составлено из следующих частей:
2
, за которыми следуют 73
- 99
(последняя часть описана выше),
[34]
, за которыми следуют любые две цифры или
5
и 00
- 48
(последняя часть описана выше)