При использовании регулярных выражений может встать задача написания шаблона, определяющего число из интервала от X до Y, а не просто числа определенной длины. Удобного механизма для этого не предусмотрено и приходится составлять громоздкие шаблоны для каждого случая. Например для промежутка от 125 до 2819 шаблон буден выглядеть следующим образом (online генератор):
1 |
(12[5-9]|1[3-9][0-9]|[2-9][0-9]{2}|1[0-9]{3}|2[0-7][0-9]{2}|28[01][0-9]) |
Очевидно, что если границы не известны заранее, а меняются во время выполнения, то для создания таких шаблонов нужна функция, которая будет составлять их по указанным границам промежутка. Ниже приводится миграция Python генератора https://github.com/dimka665/range-regex на Java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
package ru.flaps.framework.util; import java.util.*; /** * Вспомогательный генератор шаблонов регулярных выражений и их частей * <span class="hide">Created 31.10.13</span> * @author greymag * @link https://github.com/dimka665/range-regex */ public class RegExpGenerator { /** * Функция для генерации регулярного выражения, под которое подпадает * любое число в промежутке между минимальным и максимальным включительно * @param min минимальное значение * @param max максимальное значение * @return шаблон */ public static String intRange(final Integer min, final Integer max) { /* > intRange(12, 345) '1[2-9]|[2-9]\d|[1-2]\d{2}|3[0-3]\d|34[0-5]' */ final List<String> subpatterns = new ArrayList<String>(); Integer start = min; for (final Integer stop : split2Ranges(min, max)) { subpatterns.add(range2Pattern(start, stop)); start = stop + 1; } String listString = ""; for (int i = 0; i < subpatterns.size(); ++i) { if (i > 0) listString += "|"; listString += subpatterns.get(i); } return listString; } private static List<Integer> split2Ranges(final Integer min, final Integer max) { final Set<Integer> stops = new HashSet<Integer>(); stops.add(max); Integer ninesCount = 1; Integer stop = fillByNines(min, ninesCount); while (min <= stop && stop < max) { stops.add(stop); ninesCount += 1; stop = fillByNines(min, ninesCount); } Integer zerosCount = 1; stop = fillByZeros(max, zerosCount) - 1; while (min < stop && stop < max) { stops.add(stop); zerosCount += 1; stop = fillByZeros(max, zerosCount) - 1; } final List<Integer> list = new ArrayList<Integer>(stops); Collections.sort(list); return list; } private static Integer fillByNines(final Integer integer, final Integer ninesCount) { final String integerStr = integer.toString(); final String prefix = ninesCount > integerStr.length() ? "" : integerStr.substring(0, integerStr.length() - ninesCount); return Integer.parseInt(prefix + stringOfSize('9', ninesCount)); } private static Integer fillByZeros(final Integer integer, final Integer zerosCount) { return integer - integer % (int)Math.pow(10, zerosCount); } private static String range2Pattern(final Integer start, final Integer stop) { String pattern = ""; Integer anyDigitCount = 0; final String startStr = start.toString(); final String stopStr = stop.toString(); for (int i = 0; i < startStr.length(); ++i) { final String startDigit = startStr.substring(i, i + 1); final String stopDigit = stopStr.substring(i, i + 1); if (startDigit.equals(stopDigit)) { pattern += startDigit; } else if (!startDigit.equals("0") || !stopDigit.equals("9")) { pattern += String.format("[%s-%s]", startDigit, stopDigit); } else { anyDigitCount++; } } if (anyDigitCount > 0) pattern += "\\d"; if (anyDigitCount > 1) pattern += String.format("{%d}", anyDigitCount); return pattern; } private static String stringOfSize(char ch, int size) { final char[] array = new char[size]; Arrays.fill(array, ch); return new String(array); } } |
Пример использования:
1 2 3 4 5 6 7 8 9 |
final String numPattern = RegExpGenerator.intRange(10, 133); // numPattern = 1\d|[2-9]\d|1[0-2]\d|13[0-3] Boolean match; match = "Hello, my value is 134!".matches("Hello, my value is (" + numPattern + ")!"); // match = false match = "Hello, my value is 119!".matches("Hello, my value is (" + numPattern + ")!"); // match = true |