import { repeat } from 'lodash'; import { charsToCodes } from '../common/stringUtils'; const otherChars = 'ąăãçćıłńęśóöøğüțţťżź'; const wordBreakRU = `[^a-zA-Z\u0400-\u04FF${otherChars}}]`; const wordStartRU = `(?:^|${wordBreakRU})`; const wordEndRU = `(?=$|${wordBreakRU})`; function createBadWords(fast: boolean) { const emoji = fast ? '*' : '😀-🙏☀-⛿✀-➿🚀-🛶⬀-⯯🌀-🗿'; const separators1 = `:;!|\`"@#$%^&'*,._=+~\\-`; // \\(\\)\\{\\}\\]\\[ const separators2 = `${separators1}\\(\\)/\\\\`; const sep = `[ ${emoji}${separators2}]`; const sep2 = `[${emoji}${separators2}]`; const sep3 = `[${emoji}${separators1}]`; const sep4 = `[${emoji}${separators1}\\(\\)\\{\\}\\]\\[]`; const sep5 = `[ ${emoji}${separators1}\\(\\)\\{\\}\\]\\[]`; const sep2OrNum = `[0-9${emoji}${separators2}]`; const onlyLetterT = fast ? 't' : 'tţțťтᴛ'; const letter = { a: '[aаáα@4åα]', b: '[bв🅱]', c: '[cсćčçḉĉɕċƈȼ¢ς©ᴄ<]', e: '[eе3єεęėëê€é]', f: '[fғƒꜰ]', g: '[gɢ]', h: '[hн]', i: '[ıιi!1íĭǐîïḯịȉìỉȋīįᶖɨĩḭᴉᵢ¡İ|🕯ɪ]', k: '[kĸкḱǩķⱪꝃḳƙḵᶄꝁꝅʞκᴋ]', n: '[nηɴñń]', o: '[o○о0σõø🍪🥚°]', p: '[pр]', s: '[sş5$š]', ss: fast ? 'ss' : '(?:ss|ß)', t: `[${onlyLetterT}^7]`, u: '[υuúŭǔûṷüǘǚǜǖṳụűȕùủưứựừửữȗūṻųᶙůũṹṵᴜ]', x: '[xх]', ь: '[ьЪ]', }; if (fast) { Object.keys(letter).forEach(key => { (letter as any)[key] = (letter as any)[key].replace(/[^\u0020-\u007e]/g, ''); }); } const anyD = '(?:d|\\|\\))'; const anyH = '(?:h|\\|-\\|)'; const anyK = '(?:k|\\|<)'; const anyL = '(?:l|\\|_)'; const anyN = '(?:n|\\|\\\\\\|)'; const anyO = '(?:o|0|\\(\\))'; const anyU = '(?:u|\\|_\\||\\\\/|\\(_\\))'; const wordBreak = fast ? `[^a-zA-Z]` : wordBreakRU; const wordStart = `(?:^|${wordBreak})`; const wordEnd = `(?=$|${wordBreak})`; // sp const oó = fast ? 'o' : 'oó'; // pr const ã = fast ? 'a' : 'aã'; const á = fast ? 'a' : 'aá'; // ro const ă = fast ? 'a' : 'aă'; const ț = fast ? 't' : 'tț'; // pl const ą = fast ? 'a' : 'aą'; const ę = fast ? 'e' : 'eę'; const ć = fast ? 'c' : 'cć'; const ń = fast ? 'n' : 'nń'; const ł = fast ? 'l' : 'lł'; const ó = fast ? 'u' : 'uó'; const ś = fast ? 's' : 'sś'; function separeted(letters: string, separator = sep): string { return letters.split('').map(x => `${(letter as any)[x] || x}+`).join(`${separator}*`); } function baseSeparate(letters: string, sep: string, optional?: string) { return `_*${separeted(letters, sep)}${(optional ? `(?:${separeted(optional, sep)})?` : '')}_*`; } function separate(letters: string, optional?: string, separator = sep): string { return baseSeparate(letters, separator, optional); } function separate2(letters: string, optional?: string): string { return baseSeparate(letters, sep2, optional); } function alts(letters: string) { return letters.split('').map(x => `${(letter as any)[x] || x}+`).join(''); } let fuckWords: string[]; const badWords = [ // english 'aborted ?fetus', 'all?(?:uh|ah ?u?a?|uah) ?a+c?k(?:ba+r*)?', '(?][-~]*', // penis ascii art '8==[|]?[oD]', // penis ascii art '8[ =]{2,}D', // penis ascii art '(?:^| )[.][i|][.](?: |$)', // penis ascii art 'c[=-]{3,}3', '(?:^| )n [i!] g g [e3] s [t^](?: |$)', `(? tryRegex(`\\b(?:${values.join('|')})\\b`, 'ugi'); const replaceRegexRU = (values: string[]) => tryRegex(`${wordStartRU}(?:${values.join('|')})${wordEndRU}`, 'ugi'); const replaceRegexOther = (values: string[]) => tryRegex(`(?:${values.join('|')})`, 'ugi'); const replaceRegexSpecific = (values: string[]) => tryRegex(`(?:${values.join('|')})`, 'ug'); const testRegex = (values: string[]) => tryRegex(`\\b(?:${values.join('|')})\\b`, 'ui'); const testRegexRU = (values: string[]) => tryRegex(`${wordStartRU}(?:${values.join('|')})${wordEndRU}`, 'ui'); const testRegexOther = (values: string[]) => tryRegex(`(?:${values.join('|')})`, 'ui'); const testRegexSpecific = (values: string[]) => tryRegex(`(?:${values.join('|')})`, 'u'); const regexReplace = replaceRegex(unicode.all); const regexReplaceRU = replaceRegexRU(unicode.foreign); const regexReplaceOther = replaceRegexOther(unicode.other); const regexReplaceSpecific = replaceRegexSpecific(unicode.specific); const regexReplaceFast = replaceRegex(ascii.all); const regexReplaceRUFast = replaceRegexRU(ascii.foreign); const regexReplaceOtherFast = replaceRegexOther(ascii.other); const regexReplaceSpecificFast = replaceRegexSpecific(ascii.specific); const regexTest = testRegex(unicode.all); const regexTestRU = testRegexRU(unicode.foreign); const regexTestOther = testRegexOther(unicode.other); const regexTestSpecific = testRegexSpecific(unicode.specific); const regexTestFast = testRegex(ascii.all); const regexTestRUFast = testRegexRU(ascii.foreign); const regexTestOtherFast = testRegexOther(ascii.other); const regexTestSpecificFast = testRegexSpecific(ascii.specific); const regexTestFuck = testRegex(unicode.fuck); const regexReplaceRUSingle = tryRegex(`${unicode.foreign.join('|')}`, 'ugi'); const regexReplacePartial = tryRegex(`${[ ...unicode.all, ...unicode.foreign, ...unicode.other, ...unicode.specific ].join('|')}`, 'ugi'); type Replacer = (match: string) => string; const defaultReplacer: Replacer = match => repeat('*', match.length); const createReplacerRU = (replacer = defaultReplacer): Replacer => match => match.replace(regexReplaceRUSingle, replacer); function canUseFast(text: string) { return isAscii(text); } function slowReplace(text: string, replacer: Replacer, replacerRU: Replacer) { return text .replace(regexReplace, replacer) .replace(regexReplaceRU, replacerRU) .replace(regexReplaceOther, replacer) .replace(regexReplaceSpecific, replacer); } function fastReplace(text: string, replacer: Replacer, replacerRU: Replacer) { return text .replace(regexReplaceFast, replacer) .replace(regexReplaceRUFast, replacerRU) .replace(regexReplaceOtherFast, replacer) .replace(regexReplaceSpecificFast, replacer); } export function createFilter(replacer = defaultReplacer) { const replacerRU = createReplacerRU(replacer); return (text: string) => canUseFast(text) ? fastReplace(text, replacer, replacerRU) : slowReplace(text, replacer, replacerRU); } function slowTest(text: string) { return regexTest.test(text) || regexTestRU.test(text) || regexTestOther.test(text) || regexTestSpecific.test(text); } function fastTest(text: string) { return regexTestFast.test(text) || regexTestRUFast.test(text) || regexTestOtherFast.test(text) || regexTestSpecificFast.test(text); } export function hasBadWords(text: string) { return canUseFast(text) ? fastTest(text) : slowTest(text); } export function hasFuck(text: string) { return regexTestFuck.test(text); } export const filterBadWords = createFilter(); export function filterName(name: string) { const filtered = filterBadWords(name); return name === filtered ? name : repeat('*', name.length); } export function filterBadWordsPartial(text: string, replacer = defaultReplacer): string { return text.replace(regexReplacePartial, replacer); } export function findMatch(text: string): string | undefined { return unicode.all.find(x => (tryRegex(`\\b(?:${x})\\b`, 'ui')).test(text)) || unicode.foreign.find(x => (tryRegex(`${wordStartRU}(?:${x})${wordEndRU}`, 'ui')).test(text)) || unicode.other.find(x => (tryRegex(`${x}`, 'u')).test(text)) || unicode.specific.find(x => (tryRegex(`${x}`, 'u')).test(text)); } export function createMatchEntries() { return [ ...unicode.all.map(line => ({ line, regex: tryRegex(`\\b(?:${line})\\b`, 'ui') })), ...unicode.foreign.map(line => ({ line, regex: tryRegex(`${wordStartRU}(?:${line})${wordEndRU}`, 'ui') })), ...unicode.other.map(line => ({ line, regex: tryRegex(line, 'ui') })), ...unicode.specific.map(line => ({ line, regex: tryRegex(line, 'u') })), ]; }