mirror of
https://github.com/wassname/talk.git
synced 2026-07-28 11:27:05 +08:00
Generate RegExp from phrases
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user