#javascript #regex #text #dynamic #match
#javascript #регулярное выражение #текст #динамический #совпадение
Вопрос:
Каков наилучший способ создать динамическое регулярное выражение для соответствия определенному набору символов (символы и их порядок предоставляются во время выполнения).
character set: abcd
character format: ??j? (question mark represents a a character from character set)
Пример
abjd = match
bdja = match
dbja = match
ab = no match
aajd = no match
abjdd = no match
abj = no match
Я создал конструктор регулярных выражений (на js) следующим образом:
// characters are the character set
// wordFormat is the character format
// replace(str, search, replacement) replaces search in str with replacement
var chars = "[" characters "]{1}";
var afterSpecialConversion = replace(wordFormat, "?", chars);
var myRegex = new RegExp("^" afterSpecialConversion "$", "gi");
К сожалению, это не приводит к достижению результата, так как не учитывает повторяющиеся элементы. Я думал об использовании соответствующих групп, чтобы избежать дубликатов, однако я не знаю, как отрицать уже существующую группу символов из оставшейся части набора.
Также данный набор символов aabcd
now a
может существовать дважды. Есть какие-нибудь предложения?
Ответ №1:
Ваш подход к построению регулярных выражений правильный (хотя и немного запутанный в обслуживании, поэтому тщательно документируйте его), но недостаточно сложный. Что вам нужно сделать, так это использовать предварительные просмотры.
Я привел пример регулярного выражения в Regex101 для демонстрации в вашем вопросе.
Более общий принцип заключается в замене каждого набора n
вопросительных знаков шаблоном, соответствующим этому:
(?:([<chars>])(?!.*<m>)){<n>}
Где <chars>
— набор символов, который вы хотите использовать, m
— индекс набора вопросительных знаков (начиная с 1 — подробнее об этом чуть позже), а <n>
— количество вопросительных знаков в группе. Это приводит к коду regex-builder, который выглядит следующим образом:
function getRe(pattern, chars) {
var re = "^";
var qMarkGroup = 1;
var qMarkCount = 0;
for (var index in pattern) {
var char = pattern[index];
if (char === "?") {
qMarkCount = 1;
} else {
if (qMarkCount > 0) {
re = "(?:([" chars "])(?!.*\" qMarkGroup ")){" qMarkCount "}" char;
qMarkCount = 0;
qMarkGroup = 1;
}
}
}
// Need to do this again in case we have a group of question marks at the end of the pattern
if (qMarkCount > 0) {
re = "(?:([" chars "])(?!.*\" qMarkGroup ")){" qMarkCount "}";
}
re = "$";
return new Regexp(re, "gi");
}
Очевидно, что это определение функции очень подробное, чтобы продемонстрировать задействованные принципы. Не стесняйтесь использовать его в гольф (но не забывайте следить за проблемами с оградой, которые я описал в комментариях).
Кроме того, обязательно очистите входные данные. Это пример, который сломается, если кто-то, например, вставит ]
в chars
.