Created
March 22, 2019 18:52
-
-
Save lionel-rowe/72a19bf346858ede6f406ad20e7c157a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Concepts covered: | |
concept | syntax | |
---------------------------------|-------------------------- | |
testing for a match | test | |
replacing matches | replace | |
...with a string | replace(re, '...') | |
...with a function | replace(re, m => ...) | |
character classes | [] | |
non-capturing groups | (?:) | |
capturing groups | () | |
numeric reference | \1 | |
alternation | | | |
0 or more operator | * | |
1 or more operator | + | |
quantifiers with minimum bounds | {n,} | |
space and non-space | \s and \S | |
case-insensitive flag | i | |
global flag | g | |
start | ^ | |
end | $ | |
*/ | |
// test generation | |
const spamPhrases = [ | |
'viagra', 'free money', 'work from home', 'stock alert', 'dear friend' | |
]; | |
const mangleMap = { | |
a: [ 'a', '@', '4' ], | |
b: [ 'b', '8' ], | |
c: [ 'c', '{', '[', '(' ], | |
e: [ 'e', '3' ], | |
g: [ 'g', '9' ], | |
i: [ 'i', '1', '|' ], | |
o: [ 'o', '0' ], | |
s: [ 's', '5' ], | |
t: [ 't' , '7' ], | |
z: [ 'z', '2' ] | |
}; | |
const tests = [ | |
[ 'Hi Michelle,', false ], | |
[ 'The PPT from the meeting is attached', false ], | |
[ 'Are you free on Wednesday 19th?', false ], | |
[ 'I\'ll see you at work tomorrow.', false ], | |
[ 'This may be gibberish, but it\'s harmless gibberish', false ], | |
[ '', false ] | |
]; | |
const randInt = max => Math.floor(Math.random() * (max + 1)); | |
const manglePhrase = phrase => { | |
const mangledPhrase = phrase.split('').map(char => { | |
const mangledChars = mangleMap[char]; | |
if (!mangledChars) return char; | |
else { | |
const len = mangledChars.length; | |
const c = mangleMap[char][randInt(len - 1)]; | |
return c[randInt(1) === 1 ? 'toUpperCase' : 'toLowerCase'](); | |
} | |
}); | |
return mangledPhrase.join(' '.repeat(randInt(2))); | |
}; | |
spamPhrases.forEach(phrase => { | |
for (let i = 0; i < 5; i++) { | |
const mangled = manglePhrase(phrase); | |
tests.push([mangled, true]); | |
} | |
}); | |
// model answer | |
// - student will produce something functionally equivalent | |
// but using regex literals exclusively (no `makeRegex`) | |
const wordCondenser = /(?:^|\s)\S(?:(\s+)\S)(?:\1\S)*(?:$|\s)/g; | |
const spaceCondenser = /\s{2,}/g; | |
const condenseSpaces = msg => { | |
return msg | |
.replace(wordCondenser, m => m.replace(/\s+/g, '')) | |
.replace(spaceCondenser, ' '); | |
}; | |
const makeRegex = str => { | |
const content = str.split('').map(char => { | |
const mangledChars = mangleMap[char]; | |
if (!mangledChars || mangledChars.length === 1) { | |
return char; | |
} else { | |
return `[${mangledChars.join('')}]`; | |
} | |
}); | |
return new RegExp(`(?:^|\\s)${content.join('')}(?:$|\\s)`, 'i'); | |
}; | |
const blacklistRegexps = spamPhrases.map(phrase => makeRegex(phrase)); | |
/* | |
blacklistRegexps: | |
/(?:^|\s)v[i1|][a@4][g9]r[a@4](?:$|\s)/i, | |
/(?:^|\s)fr[e3][e3] m[o0]n[e3]y(?:$|\s)/i, | |
/(?:^|\s)w[o0]rk fr[o0]m h[o0]m[e3](?:$|\s)/i, | |
/(?:^|\s)[s5][t7][o0][c{[(]k [a@4]l[e3]r[t7](?:$|\s)/i, | |
/(?:^|\s)d[e3][a@4]r fr[i1|][e3]nd(?:$|\s)/i | |
*/ | |
const isSpam = msg => { | |
const spacesCondensed = condenseSpaces(msg); | |
return blacklistRegexps.some(re => re.test(spacesCondensed)); | |
}; | |
// run tests | |
tests.forEach(test => { | |
if (isSpam(test[0]) !== test[1]) console.log(test); | |
}); | |
// documentation generation | |
const spamPhrasesMD = '**Spam phrases:**\n\n' | |
+ spamPhrases.map(phrase => `* ${phrase}`).join('\n'); | |
/* | |
**Spam phrases:** | |
* viagra | |
* free money | |
* work from home | |
* stock alert | |
* dear friend | |
*/ | |
const mangleMapMD = ` | |
Character | Mangled versions | |
----------|----------------- | |
${Object.keys(mangleMap).map(key => `${key.padEnd('Character'.length, ' ')} | ${mangleMap[key].join(', ')}`).join('\n')} | |
`; | |
/* | |
Character | Mangled versions | |
----------|----------------- | |
a | a, @, 4 | |
b | b, 8 | |
c | c, {, [, ( | |
e | e, 3 | |
g | g, 9 | |
i | i, 1, | | |
o | o, 0 | |
s | s, 5 | |
t | t, 7 | |
z | z, 2 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment