Skip to content

Instantly share code, notes, and snippets.

@davidgilbertson
Created September 10, 2016 07:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidgilbertson/05e67bb9e7c3ce03b6c9be936c73920a to your computer and use it in GitHub Desktop.
Save davidgilbertson/05e67bb9e7c3ce03b6c9be936c73920a to your computer and use it in GitHub Desktop.
function checkForCloseMatch(longString, shortString) {
// too many false positives with very short strings
if (shortString.length < 3) return '';
// test if the shortString is in the string (so everything is fine)
if (longString.includes(shortString)) return '';
// split the shortString string into two at each postion e.g. g|mail gm|ail gma|il gmai|l
// and test that each half exists with one gap
for (let i = 1; i < shortString.length; i++) {
const firstPart = shortString.substring(0, i);
const secondPart = shortString.substring(i);
// test for wrong letter
const wrongLetterRegEx = new RegExp(`${firstPart}.${secondPart.substring(1)}`);
if (wrongLetterRegEx.test(longString)) {
return longString.replace(wrongLetterRegEx, shortString);
}
// test for extra letter
const extraLetterRegEx = new RegExp(`${firstPart}.${secondPart}`);
if (extraLetterRegEx.test(longString)) {
return longString.replace(extraLetterRegEx, shortString);
}
// test for missing letter
if (secondPart !== 'mail') {
const missingLetterRegEx = new RegExp(`${firstPart}{0}${secondPart}`);
if (missingLetterRegEx.test(longString)) {
return longString.replace(missingLetterRegEx, shortString);
}
}
// test for switched letters
const switchedLetters = [
shortString.substring(0, i - 1),
shortString.charAt(i),
shortString.charAt(i - 1),
shortString.substring(i + 1),
].join('');
if (longString.includes(switchedLetters)) {
return longString.replace(switchedLetters, shortString);
}
}
// if nothing was close, then there wasn't a typo
return '';
}
function checkForDomainTypo(userEmail) {
const domains = ['gmail', 'hotmail', 'outlook', 'yahoo', 'icloud', 'mail', 'zoho'];
const [leftPart, rightPart] = userEmail.split('@');
for (let i = 0; i < domains.length; i++) {
const domain = domains[i];
const result = checkForCloseMatch(rightPart, domain);
if (result) return `${leftPart}@${result}`;
}
return '';
}
function checkForNameTypo(userEmail, name) {
const [leftPart, rightPart] = userEmail.split('@');
const result = checkForCloseMatch(leftPart, name);
if (result) return `${result}@${rightPart}`;
return '';
}
function checkForCommonTypos(userInput) {
const commonTypos = [
{
pattern: /,com$/,
fix: str => str.replace(/,com$/, '.com'),
},
{
pattern: /,co\.\w{2}$/,
fix: str => str.replace(/,(co\.\w{2}$)/, '.$1'),
},
{
pattern: /@\w*$/,
fix: str => str + '.com',
},
];
typo = commonTypos.find(typo => typo.pattern.test(userInput));
if (typo) return typo.fix(userInput);
return '';
}
function checkForTypo(userInput) {
const email = userInput.email.trim().toLowerCase();
return checkForCommonTypos(email)
|| checkForDomainTypo(email)
|| checkForNameTypo(email, userInput.firstName.trim().toLowerCase())
|| checkForNameTypo(email, userInput.lastName.trim().toLowerCase());
}
function runTests() {
const testInputs = [
// correct
{firstName: '', lastName: '', email: 'first.last@example.com', expectedResult: ''},
{firstName: 'yo', lastName: 'shortname', email: 'david.gilbertson@yahoo.com', expectedResult: ''},
{firstName: 'david', lastName: 'gilbertson', email: 'david.GILBERTSON@gmail.com', expectedResult: ''},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@SOME+THING-ODD!!.com', expectedResult: ''},
{firstName: 'david', lastName: 'gilbertson', email: 'DAVId.gilbertson@outlook.com', expectedResult: ''},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@yahoo.com', expectedResult: ''},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@hotmail.com', expectedResult: ''},
{firstName: 'david', lastName: 'gilbertson', email: 'blah@unknown.com', expectedResult: ''},
{firstName: 'david', lastName: 'gilbertson', email: 'blah@hotmail.co.uk', expectedResult: ''},
// common mistakes
{firstName: 'a', lastName: 'b', email: 'a.b@example,com', expectedResult: 'a.b@example.com'},
{firstName: 'a', lastName: 'b', email: 'a.b@example,co.de', expectedResult: 'a.b@example.co.de'},
{firstName: 'a', lastName: 'b', email: 'a.b@noDotCom', expectedResult: 'a.b@nodotcom.com'},
// domain typo
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@gmial.com', expectedResult: 'david.gilbertson@gmail.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@gmal.com', expectedResult: 'david.gilbertson@gmail.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@outloik.com', expectedResult: 'david.gilbertson@outlook.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@outloook.com', expectedResult: 'david.gilbertson@outlook.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertson@yohoo.com', expectedResult: 'david.gilbertson@yahoo.com'},
// name typo
{firstName: 'david', lastName: 'gilbertson', email: 'daivd.gilbertson@xxxxx.com', expectedResult: 'david.gilbertson@xxxxx.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'daavid.gilbertson@xxxxx.com', expectedResult: 'david.gilbertson@xxxxx.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'davd.gilbertson@xxxxx.com', expectedResult: 'david.gilbertson@xxxxx.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'daivd.gilbertson@xxxxx.com', expectedResult: 'david.gilbertson@xxxxx.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertsin@xxxxx.com', expectedResult: 'david.gilbertson@xxxxx.com'},
{firstName: 'david', lastName: 'gilbertson', email: 'david.gilbertsson@xxxxx.com', expectedResult: 'david.gilbertson@xxxxx.com'},
];
testInputs.forEach(testInput => {
console.assert(
testInput.expectedResult === checkForTypo(testInput),
`${testInput.email} was not given the suggestion: ${testInput.expectedResult}`
);
});
}
runTests();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment