У меня есть интересное решение, которое должно работать как ваша оригинальная спецификация.Он не был подвергнут стресс-тестированию, я не уверен, хотите ли вы обрабатывать большой объем текста или нет, и он делает довольно много совпадений с регулярными выражениями.Не обязательно самое чистое или простое решение, но оно работает по назначению.
Особенности и ограничения:
Он обрабатывает большинство нечетных случаев в матчестрока, такая как повторяющиеся слова, очень похожие или повторяющиеся фразы и т. д.
В настоящее время вы не можете надежно иметь символы [
и ]
в исходной строке, так какони используются внутри.Если это проблема, вы должны поменять их на любой другой символ или комбинацию символов перед сопоставлением.
Для строки совпадения N
слов замена 2*N + 5
строки выполняется с использованиемрегулярные выражения различной сложности.
Соответствует словам и фразам без учета регистра, игнорируя любые несловесные символы.В то же время, он сохраняет слова со смешанным регистром и несловарные символы в результате.
Как это работает:
Сначала он ищет каждое слово отдельно и добавляет к ним их индекс в строке соответствия в квадратных скобках: word[2]
.Если слово появляется несколько раз, к нему добавляются все индексы: word[3][2][1]
.
Далее, он находит и помечает слова, которые не находятся в границах переноса, просматривая индексы окружающих слов,На отдельном шаге он удаляет индексы из этих слов.В конце концов one[1] two[2] three[3]
станет one[1] []two three[3]
.
Теперь осталось только сделать некоторые предположения в определенном порядке и обернуть слова / фразы.Взгляните на код, чтобы увидеть все выполненные замены.
Важно, что после первого шага мы никогда не сопоставляем слова напрямую, с этого момента слово просто упоминаетсякак any number of word characters before [index]
или any number of word characters after []
.Это гарантирует, что мы правильно упаковываем повторяющиеся слова / фразы.
Посмотрите на это демо .Я добавил эффект наведения, чтобы вы могли видеть, какие слова сгруппированы и обернуты вместе.
А вот сумасшедший код, наслаждайтесь!
var matchstring = 'Brown cats cannot be white cats';
var wrapstring = 'Hi bill, brown cats cannot be white cats and cows are not blue pigs, blue melons are large but not batteries charged barges with white cats carry coal, and the word "cannot" should match ';
// Pre-process matchstring to make it a flat list of words
// separated by single spaces.
matchstring = matchstring.replace(/\W+/g,' ');
var wrapStart = '<span class="wrapped">';
var wrapEnd = '</span>';
var matcharray = matchstring.split(' ');
var i, reg;
// Mark all matched words with indices
// one -> one[1]
for (i = 0; i < matcharray.length; i++) {
reg = new RegExp('\\b' + matcharray[i] + '\\b', 'ig');
wrapstring = wrapstring.replace(reg, '$&[' + i + ']');
}
// Mark all inner words
// one[1] two[2] three[3] -> one[1] []two[2] three[3]
for (i = 1; i < matcharray.length; i++) {
reg = new RegExp('\\b(\\w+)([\\]\\d\\[]*\\[' + (i - 1) + '\\][\\]\\d\\[]*)(\\W+)(\\w+)([\\]\\d\\[]*\\[' + i + '\\][\\]\\d\\[]*)(?=\\W+\\w+[\\[\\d\\]]*\\[' + (i + 1) + '\\])', 'ig');
wrapstring = wrapstring.replace(reg, '$1$2$3[]$4$5');
}
// Remove indices from inner words
// one[1] []two[2] three[3] -> one[1] []two three[3]
wrapstring = wrapstring.replace(/\[\](\w+)[\[\d\]]*/g, '[]$1');
// Start tags
// one[1] []two three[3] -> {one []two three[3]
wrapstring = wrapstring.replace(/(\w+)\[[\[\d\]]+\](\W+)\[\]/g, wrapStart + '$1$2[]');
// End tags
// {one []two three[3] -> {one []two three}
wrapstring = wrapstring.replace(/\[\](\w+\W+\w+)\[[\[\d\]]+\]/g, '$1' + wrapEnd);
// Wrap double words
// one[1] two[2] -> {one two}
wrapstring = wrapstring.replace(/(\w+)\[[\[\d\]]+\](\W+\w+)\[[\[\d\]]*\]/g, wrapStart + '$1$2' + wrapEnd);
// Orphan words
// unmatched matched[1] unmatched -> unmatched {matched} unmatched
wrapstring = wrapstring.replace(/(\w+)\[[\[\d\]]+\]/g, wrapStart + '$1' + wrapEnd);
// Remove left-over tags
// []word -> word
wrapstring = wrapstring.replace(/\[\]/g, '');
alert(wrapstring);
Соответствие частичным словам
Как уже упоминалось, после первого шага слова обрабатываются только по их добавленным индексам.Это означает, что если мы хотим сделать какое-то умное сопоставление вместо целых слов, нам просто нужно изменить регулярное выражение в первом цикле for
.Это фрагмент кода, с которым мы будем играть в этом разделе:
reg = new RegExp('\\b' + matcharray[i] + '\\b', 'ig');
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} 10 * в регулярном выражении означает соответствие границ слова, то есть начало или конец последовательности символов слова.Вот почему вышеприведенное \bword\b
регулярное выражение дает нам только целые слова, так как word
должен быть окружен границами слов.Но это не обязательно должно быть так.
Если мы хотим сопоставить все слова в тексте, начинающемся с нашего ключевого слова, мы можем изменить приведенную выше строку следующим образом:
reg = new RegExp('\\b' + matcharray[i] + '\\w*\\b', 'ig');
Это приводит к регулярному выражению \bword\w*\b
.Он соответствует всем word
последовательностям символов, за которыми следуют 0 или более дополнительных символов слова (\w*
), окруженных границами слова.Обратите внимание, что обратные слэши необходимо экранировать в строках javascript (\\
означает один \
).
В зависимости от требований мы можем легко создавать дополнительные комбинации регулярных выражений:
\bword\w*\b
соответствует словам, начинающимся с ключевого слова. \b\w*word\b
соответствует словам, заканчивающимся ключевым словом. \b\w*word\w*\b
соответствует словам, содержащим ключевое слово. \b(\w*word|word\w*)\b
соответствуетслова, оканчивающиеся или начинающиеся с ключевого слова.
Вы даже можете сказать, что хотите сопоставить только незначительные модификации слов.Например, \b\w{0,2}word\w{0,2}\b
будет соответствовать слову, только если оно имеет максимум двухбуквенный префикс и / или суффикс.Таким образом, danger
будет соответствовать endanger
, cat
будет соответствовать cats
, но can
не будет соответствовать cannot
, так как это будет 3 дополнительные буквы.
Сопоставить сложные формы множественного числа и неправильные глаголы непросто, вы можете создать огромный словарь неправильных слов на вашем сервере и предварительно обработать слово, поэтому, если пользователь вводит foot
, с помощью регулярного выражения \b(foot|feet)\b
будет соответствоватьобе формы.Более простым решением будет заботиться только о регулярных словах.Для большинства слов совпадения \bword(s|es|)\b
будет достаточно, чтобы поймать множественное число, оно также соответствует word
, words
и wordes
.Для таких слов, как fly
, регулярное выражение \bfl(y|ies)\b
выполнит эту работу.Для таких слов, как index
, регулярное выражение \bind(ex|exes|ices)\b
будет соответствовать большинству распространенных форм.
Поскольку я не очень разбираюсь в языке, я пока просто оставлю это здесь.
Подстановочные знаки во входных данных
Как и выше, очень легко добавить поддержку подстановочных знаков во входной строке.Допустим, мы хотим, чтобы пользователь ввел ?
, что означает любой символ .Если введено значение ?red
, нам просто нужно заменить ?
на \w
в нашем регулярном выражении.Например, \b\wred\b
будет соответствовать fred
и dred
.
Как и выше, вы также можете использовать несколько символов подстановки, заменив их на \w+
для одного или нескольких символов или \w*
для ноль или более символов .\bf\w+d\b
будет соответствовать fed
и feed
, \w*
будет соответствовать fd
.