Generate RegExp from phrases

This commit is contained in:
Chi Vinh Le
2017-09-14 00:10:29 +07:00
parent 6487072be1
commit fa335564ed
@@ -1,90 +1,32 @@
import React from 'react';
import {matchLinks} from '../utils';
const capturingWordSeparator = /([.\s'"?!])/;
const wordSeparator = /[.\s'"?!]/;
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
function generateRegExp(phrases) {
const inner = phrases
.map((phrase) => {
return phrase.split(/\s+/)
.map((word) => escapeRegExp(word))
.join('[\\s"?!.]+');
}).join('|');
return `(^|[^\\w])(${inner})(?=[^\\w]|$)`;
}
// markPhrases looks for `phrases` inside `body` and highlights them by returning
// an array of React Elements.
function markPhrases(body, phrases, keyPrefix) {
const tokens = body.split(capturingWordSeparator);
const phraseWords = phrases.map((phrase) => phrase.toLowerCase().split(wordSeparator));
const content = [];
let tmp = [];
for (let l = 0; l < tokens.length; l++) {
// matchedWords is > 0 when a full match was found and contains
// the range length from this index to the end of the match.
let matchedWords = 0;
// Skip word separators and ''.
if (tokens[l] !== '' && !tokens[l].match(wordSeparator)) {
for (let m = 0; m < phraseWords.length; m++) {
const words = phraseWords[m];
// We try to match the full phrase, index keeps track
// of where we are now on the tokens array while matching
// the words of the phrase.
let index = l;
for (let n = 0; n < words.length; n++, index++) {
// Skip word separators and ''.
while (index < tokens.length && (tokens[index].match(wordSeparator) || tokens[index] === '')) {
index++;
}
// No more tokens left.
if (index >= tokens.length) {
break;
}
const token = tokens[index].toLowerCase();
const word = words[n];
if (token !== word) {
break;
}
// Full match!
if (n === words.length - 1) {
// Save the matched range length into matched words.
matchedWords = index - l + 1;
break;
}
}
// We matched a word so break out the loop.
if (matchedWords) {
break;
}
}
const regexp = new RegExp(generateRegExp(phrases), 'iu');
const tokens = body.split(regexp);
return tokens.map((token, i) => {
if (i % 3 === 2) {
return <mark key={`${keyPrefix}_${i}`}>{token}</mark>;
}
// We have a match!
if (matchedWords) {
const match = tokens.slice(l, l + matchedWords).join('');
// Append whatever we have in `tmp` and clear it.
content.push(tmp.join(''));
tmp = [];
content.push(<mark key={`${keyPrefix}_${l}`}>{match}</mark>);
// Move index further if we matched more than one word.
l += matchedWords - 1;
continue;
}
// No match, we just push this into `tmp`.
tmp.push(tokens[l]);
}
// Append any non matched tokens currently in `tmp`.
content.push(tmp.join(''));
return content;
return token;
});
}
// markLinks looks for links inside `body` and highlights them by returning