Частичное совпадение строки с регулярным выражением
Предположим, что у меня есть это регулярное выражение: /abcd/Предположим, что я хочу проверить ввод пользователя в отношении этого регулярного выражения и запретить ввод недопустимых символов на входе. Когда пользователь вводит "ab", он не подходит для соответствия регулярному выражению, но я не могу запретить вводить "a", а затем "b", так как пользователь не может вводить сразу все четыре символа (кроме копирования/вставки). Так что мне нужно здесь, это частичное совпадение, которое проверяет, может ли неполная строка потенциально соответствовать регулярному выражению.
Java имеет что-то для этой цели: .hitEnd()
(описано здесь http://glaforge.appspot.com/article/incomplete-string-regex-matching). Python не делает это изначально, но имеет этот пакет, который выполняет эту работу: https://pypi.python.org/pypi/regex.
Я не нашел в нем никакого решения в js. Это было задано несколько лет назад: частичное совпадение Javascript RegEx и еще до этого: проверьте, является ли строка префиксом Javascript RegExp
PS регулярное выражение является обычным, предположим, что пользователь сам входит в само регулярное выражение, а затем пытается ввести текст, соответствующий этому регулярному выражению. Решение должно быть общим решением, которое работает для регулярных выражений, введенных во время выполнения.
Ответы
Ответ 1
Похоже, вам повезло, я уже реализовал этот материал в JS (который работает для большинства моделей - возможно, этого вам будет достаточно). См. Мой ответ здесь. Вы также найдете там рабочую демоверсию.
Здесь нет необходимости дублировать полный код, я просто укажу на общий процесс:
- Разберите входное регулярное выражение и выполните некоторые замены. Нет необходимости в обработке ошибок, так как вы не можете иметь недопустимый шаблон в объекте
RegExp
в JS. - Замените
abc
(?:a|$)(?:b|$)(?:c|$)
- Сделайте то же самое для любых "атомов". Например, группа символов
[ac]
станет (?:[ac]|$)
- Держите якоря как есть
- Держите отрицательные
Если бы JavaScript имел более сложные функции регулярного выражения, это преобразование могло быть невозможным. Но с его ограниченным набором функций он может обрабатывать большинство входных регулярных выражений. Это приведет к неправильным результатам в регулярном выражении с обратными ссылками, хотя если ваша строка ввода заканчивается в середине соответствия ^(\w+)\s+\1$
(например, сопоставление ^(\w+)\s+\1$
от hello hel
).
Ответ 2
Я думаю, что у вас должно быть 2 регулярных выражения для ввода /a?b?c?d?/
И один для тестирования в конце при вставке или выходе из ввода /abcd/
Это проверит действительный номер телефона:
const input = document.getElementById('input')
let oldVal = ''
input.addEventListener('keyup', e => {
if (/^\d{0,3}-?\d{0,3}-?\d{0,3}$/.test(e.target.value)){
oldVal = e.target.value
} else {
e.target.value = oldVal
}
})
input.addEventListener('blur', e => {
console.log(/^\d{3}-?\d{3}-?\d{3}-?$/.test(e.target.value) ? 'valid' : 'not valid')
})
<input id="input">
Ответ 3
Я сильно подозреваю (хотя я не уверен на 100%), что общий случай этой проблемы не имеет решения так же, как знаменитая проблема Тьюринга "Халтин" (см. " Неразрешимая проблема"). И даже если есть решение, скорее всего, это будет не то, что действительно хотят пользователи, и, следовательно, в зависимости от вашей строгости приведет к плохому UX.
Пример:
Предположим, что "target RegEx" - это [a,b]*c[a,b]*
также предположим, что вы создали разумный на первый взгляд "тест RegEx" [a,b]*c?[a,b]*
(очевидно, два c
в строке неверно, да?) и предположим, что текущий пользовательский ввод - aabcbb
но есть опечатка, потому что то, что действительно хотел пользователь, - aacbbb
. Существует много способов устранить эту опечатку:
- удалить
c
и добавить его до первого b
- будет работать нормально - удалить первый
b
и добавить после c
- будет работать нормально - добавьте
c
перед первым b
а затем удалите старый. Ой, мы запрещаем этот ввод как недействительный, и пользователь сойдет с ума, потому что нормальный человек не может понять такую логику.
Обратите внимание также, что ваш hitEnd
будет иметь такую же проблему, если вы не запретите пользователю вводить символы в середине поля ввода, что будет другим способом создания ужасного пользовательского интерфейса.
В реальной жизни было бы намного более сложные примеры того, что любая из ваших умных эвристик не сможет правильно учитывать и, таким образом, будет расстраивать пользователей.
Так что делать? Я думаю, что единственное, что вы можете сделать и по-прежнему получать разумный UX - это самое простое, что вы можете сделать, просто проанализируйте свой "целевой регекс" для набора допустимых символов и сделайте свой "тест RegEx" [set of allowed chars]*
. И да, если содержит "целевой регекс" .
wildcart, вы не сможете делать какую-либо разумную фильтрацию вообще.
Ответ 4
Это трудное решение для тех, кто считает, что нет никакого решения: реализовать версию python (https://bitbucket.org/mrabarnett/mrab-regex/src/4600a157989dc1671e4415ebe57aac53cfda2d8a/regex_3/regex/_regex.c?at=default&fileviewer= file-view-default) в js. Так что можно. Если у кого-то есть более простой ответ, он выиграет щедрость.
Пример использования модуля python (регулярное выражение с обратной ссылкой):
$ pip install regex
$ python
>>> import regex
>>> regex.Regex(r'^(\w+)\s+\1$').fullmatch('abcd ab',partial=True)
<regex.Match object; span=(0, 7), match='abcd ab', partial=True>
Ответ 5
Ребята, вы, вероятно, найдете эту страницу интересной:
(https://github.com/desertnet/pcre)
Это была смелая попытка: создать реализацию WebAssembly, которая будет поддерживать PCRE. Я все еще играю с этим, но я подозреваю, что это не практично. Двоичный файл WebAssembly весит ~ 300K; и если ваш JS неожиданно завершает работу, вы можете не уничтожить модуль и, следовательно, потерять значительную память.
Суть в том, что это, очевидно, то, что люди ECMAscript должны формализовать, и производители браузеров должны предоставить (благодарность разработчику WebAssembly, возможно, позоря их за то, что они попали на карту...)
Я недавно пытался использовать атрибут "pattern" элемента input [type = 'text']. Я, как и многие другие, нашел, что это разочарование, которое не будет подтверждено, пока форма не будет отправлена. Таким образом, человек будет тратить свое время, набирая (или вставляя...) многочисленные символы и перепрыгивая на другие поля, только чтобы узнать после отправки формы, что они ввели это поле неправильно. В идеале я хотел, чтобы он сразу же проверял ввод данных в поле, поскольку пользователь вводит каждую клавишу (или во время вставки...)
Хитрость в том, чтобы выполнить частичное совпадение с регулярным выражением (до тех пор, пока сотрудники ECMAscript и производители браузеров не получат его вместе с PCRE...), состоит не только в том, чтобы указать регулярное выражение в шаблоне, но и соответствующие значения шаблона в качестве атрибута данных. Если ваше поле ввода короче, чем шаблон (или input.maxLength...), он может использовать их в качестве суффикса для целей проверки. ДА -this не будет практичным для регулярных выражений со сложными случаями; но для сопоставления с шаблоном с фиксированной позицией -which обычно, что needed- хорошо (если вам нужно что-то более сложное, вы можете использовать методы, показанные в моем коде...)
Пример для адреса биткойн [Есть ли ваше внимание сейчас? -OK, а не люди, которые не верят в технологии цифровых валют...] Ключевая функция JS, которая делает это, - validatePattern. Элемент ввода в разметке HTML будет указан следующим образом:
<input id="forward_address"
name="forward_address"
type="text"
maxlength="90"
pattern="^(bc(0([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59})|1[ac-hj-np-z02-9]{8,87})|[13][a-km-zA-HJ-NP-Z1-9]{25,34})$"
data-entry-templates="['bc099999999999999999999999999999999999999999999999999999999999','bc1999999999999999999999999999999999999999999999999999999999999999999999999999999999999999','19999999999999999999999999999999999']"
onkeydown="return validatePattern(event)"
onpaste="return validatePattern(event)"
required
/>
[Кредит переходит к этому сообщению: "RegEx соответствует адресам Биткойн?
"Примечание для приверженцев старой школы биткойнов, которые будут осуждать использование нуля в регулярном выражении здесь -it, просто пример для выполнения ПРЕДВАРИТЕЛЬНОЙ проверки; сервер, принимающий адрес, переданный браузером, может выполнить вызов RPC после форма сообщения, чтобы проверить его более строго. Настройте свое регулярное выражение в соответствии с.]
Точный выбор символов в шаблоне ввода данных был немного произвольным; но они должны были быть такими, чтобы, если ввод, который вводит или вставляет пользователь, по-прежнему был неполным по длине, он использовал их как оптимистическую замену, и до сих пор ввод будет считаться действительным. В этом примере для последнего из шаблонов ввода данных ('19999999999999999999999999999999999') это было "1", за которым следуют 39 девяток (видя, что спецификация регулярного выражения "{25,39}" диктует, что максимум 39 цифр во втором символьном интервале/группе...) Поскольку ожидалось, что -the префикс "bc" будет иметь две формы и более старый "1"/"3" prefix- Я предоставил несколько шаблонов для средство проверки, которое нужно попробовать (если оно проходит только один из них, оно проверяет...) В каждом случае шаблона я предоставлял максимально длинный шаблон, чтобы обеспечить максимально допустимую возможность с точки зрения длины.
Если бы вы создавали эту разметку на сервере динамического веб-контента, пример с шаблонными переменными (a la django...) будет выглядеть так:
<input id="forward_address"
name="forward_address"
type="text"
maxlength="{{MAX_BTC_ADDRESS_LENGTH}}"
pattern="{{BTC_ADDRESS_REGEX}}" {# base58... #}
data-entry-templates="{{BTC_ADDRESS_TEMPLATES}}" {# base58... #}
onkeydown="return validatePattern(event)"
onpaste="return validatePattern(event)"
required
/>
[Имейте в виду: я пошел в более глубокий конец бассейна здесь. С тем же успехом вы можете использовать это для более простых шаблонов проверки.]
И если вы предпочитаете не использовать атрибуты события, а прозрачно привязать функцию к событиям элемента при загрузке документа -knock самостоятельно.
Вы заметите, что нам нужно указать validatePattern для трех событий:
Клавиша для перехвата клавиш удаления и возврата.
Вставка (буфер вставляется в значение поля, и если он работает, он принимает его как действительный; если нет, вставка не выполняется...)
Разумеется, я также учел частичное выделение текста в поле, указав, что ключевая запись или вставленный текст заменит выделенный текст.
А вот ссылка на [код, свободный от зависимостей], который творит чудеса:
https://gitlab.com/osfda/validatepattern.js
(Если это вызовет интерес, я объединю конструктивные и практические предложения и предоставлю более подробную информацию...)
PS: пакет инкрементных регулярных выражений, размещенный выше Лукасом Тресневским:
Похоже, не были обновлены? (Я видел признаки того, что он подвергался модификации??)
Не подвергается браузерной проверке (попытался сделать это с ним, чтобы пнуть шины на нем -it был беспорядок в модуле; приглашаем кого-либо еще здесь, чтобы опубликовать версию с браузерной проверкой для тестирования. Если это сработает, я интегрирую это с моими хуками проверки ввода и предложите его в качестве альтернативного решения...) Если вам удастся получить его в браузере, возможно, если вы поделитесь точными шагами, которые были необходимы, это также наставит всех на этом посте. Я пытался использовать пакет esm для исправления несовместимости версий, с которыми сталкивался browserify, но ничего не вышло...