В Javascript я определил регулярное выражение, и теперь пользователь вводит строку. Я хочу сказать ему, может ли его строка соответствовать RegExp, если он продолжит печатать, или он уже ошибается. Например:
var re = /a*b/;
"a".isPrefixOf( re ); // true
"x".isPrefixOf( re ); // false
Как могла бы выглядеть реализация isPrefixOf?
Обновлять: Спасибо за ваши ответы, обеспечение защиты от префиксов регулярных выражений, как предлагает Брэд, кажется хорошим обходным путем. Но я все еще пытаюсь найти общее решение.
Может быть, так: мы создаем новое регулярное выражение с вводом пользователя, за которым следует .*. Это регулярное выражение описывает все слова, которые пользователь может вводить. Если пересечение этого созданного регулярного выражения и исходного регулярного выражения пусто, значит, пользователь уже находится на неправильном пути. Если нет, то он в порядке. Например:
var re = /a*b/;
var sInput = "a";
var reInput = new RegExp( sInput + ".*" );
reIntersection = re.intersect( reInput );
reIntersection.isEmpty(); // false
intersect() возвращает новое регулярное выражение, которое принимает только слово, которое будут принимать как re, так и reInput. Функция еще не существует, но мы можем реализовать ее с опережением:
RegExp.prototype.intersect = function( pattern2 ) {
return new RegExp( '(?=' + this.source + ')' + pattern2.source );
}
Что остается открытым, так это функция isEmpty(). Как мы могли проверить, соответствует ли регулярное выражение Javascript какому-либо слову или оно пустое?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Сначала вы определяете свое регулярное выражение как: var re = new RegExp (/ ^ (здесь regexp) $ /);
в событии onKeypress вы проверяете регулярное выражение следующим образом:
text.match (regexp) - где текст - это введенная строка.
Это понятно?
Одним из способов сделать это может быть привязка к событию onKeyUp текстового поля и .контрольная работа текста к регулярному выражению. Я, конечно, предполагаю, что вы хотите выполнить сопоставление регулярных выражений. Я не уверен, что это именно то, что вам нужно, на самом деле ваш код:
"a".isPrefixOf( re ); // true
никогда не будет совпадать, так как он должен иметь следующий символ «b» (вы можете изменить регулярное выражение). Например, этот код будет проверять любую строку, соответствующую этому формату:
a-n(n)-b
Вот код, сохраните его как страницу и загрузите в свой браузер:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "it">
<body>
<input type = "text" size = "20" id = "txtData" onkeyup = "showResult()" />
<div id = "dvResult" />
</body>
</html>
<script type = "text/javascript">
//<![CDATA[
theRegExp = /^a\-\d{1,2}\-b$/;
function isPrefixOf( aText, aRegExp )
{
return aRegExp.test( aText );
}
function showResult()
{
res = document.getElementById( "dvResult" );
res.innerHTML = isPrefixOf( document.getElementById( "txtData" ).value, theRegExp ) ? "Correct" : "Bad input";
}
//]]>
</script>
Вам следует прочитать вопрос более внимательно. Не спрашивает, как вызвать совпадение. Спрашивает, как написать сопоставитель.
Вот почему я выделил это примечание жирным шрифтом!
Хотя вопрос можно было бы сформулировать лучше, я думаю, что его нетрудно понять. Какой голос вы хотите, чтобы я удалил?
Очень интересный вопрос. В моем быстром поиске я не нашел ничего предопределенного (даже в Perl), которое решало бы эту проблему.
Обновлено: Ой, похоже, в Java есть что-то похожее, называемое hitEnd () - см. Ответ Алана М. HitEnd () сообщает, что результат match () (истинный или ложный) может быть изменен дополнительным вводом. В книге «Освоение регулярных выражений» говорится, что это не очень надежно (не знаю, почему, страница 392 недоступна в книгах Google).
В зависимости от того, какие функции регулярных выражений вы используете, быстрый взлом, например, написание каких-то префиксов вашего регулярного выражения:
например для a + a * b + c ваши префиксы будут такими:
a+ a+a* a+a*b+ a+a*b+c
и попробуйте сопоставить любой из них с вашей строкой, может сработать. Этот быстрый прием затруднен, если вы используете оператор выбора, если вы используете оператор диапазона {n, m} или обратные ссылки.
При этом я думаю, что хорошее решение - немного изменить алгоритм сопоставления.
Обычно используемый алгоритм сопоставления представляет собой алгоритм отслеживания с возвратом (который хорошо работает на практике, даже если поведение в худшем случае является экспоненциальным). Этот алгоритм успешно завершается всякий раз, когда он достигает конца регулярного выражения (даже если не вся строка была использована). Что вам нужно сделать, так это изменить условие завершения так, чтобы оно также успешно завершалось, когда оно потребляет весь ввод.
При этом вам, вероятно, придется реализовать алгоритм на JavaScript. Надеюсь, это станет частью таких библиотек, как JQuery.
Для получения дополнительных ссылок и теории алгоритма ознакомьтесь с этой статьей:
http://swtch.com/~rsc/regexp/regexp1.html
(даже если он опровергает алгоритм обратного отслеживания и предлагает алгоритм на основе FA (но FA не может обрабатывать обратные ссылки)).
Я думаю, что лучше всего сделать ваше Regex устойчивым к префиксу. Для приведенного вами примера, /a*b/, я думаю, вы могли бы использовать /a*b?/.test(userinput). Для более сложных шаблонов это может стать все труднее, но я все же думаю, что это можно сделать, вложив каждое подвыражение в серию необязательных квантификаторов (?). Например:
/a*bcd*e/
Регулярное выражение префикса может быть:
/a*(b(c(d*e?)?)?)?/
Это немного беспорядочно, но, я думаю, решит вашу проблему довольно хорошо.
Это отличная идея (вы получаете голос "за"), но я думаю, что она быстро разрушается для более сложных моделей. Как создать префиксное регулярное выражение для следующего шаблона? / a (bc | BC) d /
Кажется, что люди поровну интерпретируют этот вопрос, поэтому я продемонстрирую эту концепцию на примере Java.
import java.util.regex.*;
public class Test
{
public static void main(String[] args) throws Exception
{
tryMatch("^a*b+$", "a", "ab", "abc");
}
public static void tryMatch(String regex, String... targets)
{
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher("");
System.out.printf("%nregex: %s%n", regex);
System.out.printf("target | matches() | hitEnd()%n");
for (String str : targets)
{
m.reset(str);
System.out.printf("%-6s | %-9B | %-9B%n",
str, m.matches(), m.hitEnd());
}
}
}
выход:
regex: ^a*b+$
target | matches() | hitEnd()
a | FALSE | TRUE
ab | TRUE | TRUE
abc | FALSE | FALSE
Целевая строка «a» не совпадает, потому что для регулярного выражения требуется хотя бы один b, но это может быть префикс успешного совпадения, поэтому hitEnd() возвращает true. Строка «ab» содержит все, что требуется для совпадения, но она также будет соответствовать, если мы добавим больше b в конец, поэтому hitEnd() по-прежнему возвращает true. С «abc» попытка сопоставления не удалась до того, как достигнет конца целевой строки, поэтому регулярное выражение не может сопоставить ни одну строку, которая начинается с «abc».
Насколько мне известно, в Javascript нет ничего похожего на метод Java hitEnd(), но его можно подделать. Если кто знает как, то это будет тот самый вопиющий задира, Стивен Левитан.
Вам следует прочитать вопрос более внимательно. Не спрашивает, как вызвать совпадение. Спрашивает, как написать сопоставитель.