Javascript regular expression spaces check - javascript

I have a question for you that I can't seem to figure out on my own.
Let's say that I want to validate a users first name. Some can contain multiple parts like "John William" with a space in between. What I want to do is match the input to a regular expression that seeks out if the name contains any spaces at the beginning, or at the end.
Further more the regular expression should check if there are ONLY letters (a-z, both lower and upper case) in the name.
This is what I came up with so far:
/^\s+[A-z]+|[A-z]+\s+$/
But somehow this regular expression does not take any other characters (such as dash, underscore, ampersand, etc.) into notice. Basically all it does is tell me wether there are spaces at the beginning or at the end of the input.
Can anyone help me out here?
EDIT:
Here's the full code i'm using:
$(document).ready(function() {
$('#firstname, #lastname').bind('keyup blur', function() {
var _input = $(this);
var _illegal = Validate_Regexp(_input.val(), /^\s+[A-Za-z]+|[A-Za-z]+\s+$/);
if (_illegal == true) {
$("#"+_input.attr('id')+".validator").css({
'background-image' : 'url(./images/icons/bullet_red.png)',
});
} else {
$("#"+_input.attr('id')+".validator").css({
'background-image' : 'url(./images/icons/bullet_green.png)',
});
}
});
});
function Validate_Regexp($value, $regexp) {
return $regexp.test($value);
}
EDIT 2:
I'm going with Charlie's answer, however his answer forced me to have 2 parts of the name, instead of as much as I'd like.
I changed the code from:
var isLegal = /^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test(stringToTest);
to:
var isLegal = /^[a-zA-Z]+(\s[a-zA-Z]+)*?$/.test(stringToTest);

I noticed that you are checking for strings that are illegal. Let's turn it around and check for a string that is valid:
var isValid = /^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test(stringToTest);
Results:
/^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test("john doe"); // true
/^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test("john"); // true
/^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test("john d_oe"); // false
/^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test(" john doe "); // false
/^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test(" john doe"); // false
/^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test("john doe "); // false
/^[a-zA-Z]+(\s+[a-zA-Z]+)?$/.test("john "); // false
Translated to your existing code:
var isValid = Validate_Regexp(_input.val(), /^[a-zA-Z]+(\s+[a-zA-Z]+)?$/);
if (isValid) {
$("#"+_input.attr('id')+".validator").css({
'background-image' : 'url(./images/icons/bullet_blue.png)',
});
} else {
$("#"+_input.attr('id')+".validator").css({
'background-image' : 'url(./images/icons/bullet_red.png)',
});
}

You really don't care if there are leading or trailing spaces, or how many there are in between the names, all that stuff is very easy to manage without bothering the user.
So a suitable function might be:
function checkNames(s) {
// Remove excess spaces
s.replace(/(^\s*)|(\s*$)/g, '').replace(/\s+/g, ' ');
// Check remaining content
return /[a-z]+ [a-z]+/i.test(s);
}
But note that names can be hyphenated and contain numbers (e.g. William Gates the 3rd) or letters other than those in the English alphabet. So usually you let users type whatever they want and just deal with the spaces.

Related

Caps and Lowercase input that also generates in output

I've been trying to put together an input where the text automatically capitalizes the first letter of each word and makes all other letters lowercase for that word. I had some success using that for just making everything lower case after the first letter for the input with this:
<input type = "text" size="8" name="textfield1" id="textfield1" />
with the javascript being
document.getElementById('textfield1').addEventListener("keyup", () => {
var inputValue = document.getElementById('textfield1')['value'];
if (inputValue[0] === ' ') {
inputValue = '';
} else if (inputValue) {
inputValue = inputValue[0].toUpperCase() + inputValue.slice(1).toLowerCase();
}
document.getElementById('textfield1')['value'] = inputValue;
});
I tried adding map(), split(), and join() in various ways based off of lessons I've found (I'm learning on my own, no formal training since high school) for use in a string with the console.log methods but I'm confused on how I can apply this to an input. It would take too long to note everything I've tried but one thing I did was this:
document.getElementById('textfield1').addEventListener("keyup", () => {
var inputValue = document.getElementById('textfield1')['value'];
if (inputValue[0] === ' ') {
inputValue = '';
} else if (inputValue) {
input.content = input.content.split(' ').map(function(inputValue) {
return inputValue[0].toUpperCase() + inputValue.slice(1).toLowerCase();
}).join(' ');
}
document.getElementById('textfield1')['value'] = inputValue;
});
I'm not sure what I'm missing here. I'm sure there's something that I'm not seeing or understanding. I also tried looking to see if there was something similar listed on here or elsewhere in relation to this and inputs but I didn't see anything specific to what I was looking for.
I want the input to remain the same for what comes up with the output into another box when it gets copied over.
Example of what I'm trying to do is:
input of textfield: heLlo OuT thERe!
output to another textarea with the click of a button: Hello Out There!
Your second version would be correct. However in this code:
else if (inputValue) {
input.content = input.content.split(' ').map(function(inputValue) {
return inputValue[0].toUpperCase() + inputValue.slice(1).toLowerCase();
}).join(' ');
}
You started to use some input.content instead of the inputValue variable. Most probably yout mistake lies there.
You can use this regex replace to change a sentence to Proper Case:
const regex = /\b(\w)(\w*)/g;
const input = 'Fix this lower and UPPER to Proper'
let result = input.replace(regex, function(m, c1, c2) {
return c1.toUpperCase() + c2.toLowerCase()
});
console.log('result: ', result);
// => 'Fix This Lower And Upper To Proper'
Explanation of regex:
\b -- word boundary
(\w) -- capture group 1: a singe word character
(\w*) --capture group 2: zero to multiple word characters
g -- flag for global, e.g. run pattern multiple times
replace function: parameter c1 contains capture group 1, c2 contains capture group 2

is there a way for the content.replace to sort of split them into more words than these?

const filter = ["bad1", "bad2"];
client.on("message", message => {
var content = message.content;
var stringToCheck = content.replace(/\s+/g, '').toLowerCase();
for (var i = 0; i < filter.length; i++) {
if (content.includes(filter[i])){
message.delete();
break
}
}
});
So my code above is a discord bot that deletes the words when someone writes ''bad1'' ''bad2''
(some more filtered bad words that i'm gonna add) and luckily no errors whatsoever.
But right now the bot only deletes these words when written in small letters without spaces in-between or special characters.
I think i have found a solution but i can't seem to put it into my code, i mean i tried different ways but it either deleted lowercase words or didn't react at all and instead i got errors like ''cannot read property of undefined'' etc.
var badWords = [
'bannedWord1',
'bannedWord2',
'bannedWord3',
'bannedWord4'
];
bot.on('message', message => {
var words = message.content.toLowerCase().trim().match(/\w+|\s+|[^\s\w]+/g);
var containsBadWord = words.some(word => {
return badWords.includes(word);
});
This is what i am looking at. the var words line. specifically (/\w+|\s+|[^\s\w]+/g);.
Anyway to implement that into my const filter code (top/above) or a different approach?
Thanks in advance.
Well, I'm not sure what you're trying to do with .match(/\w+|\s+|[^\s\w]+/g). That's some unnecessary regex just to get an array of words and spaces. And it won't even work if someone were to split their bad word into something like "t h i s".
If you want your filter to be case insensitive and account for spaces/special characters, a better solution would probably require more than one regex, and separate checks for the split letters and the normal bad word check. And you need to make sure your split letters check is accurate, otherwise something like "wash it" might be considered a bad word despite the space between the words.
A Solution
So here's a possible solution. Note that it is just a solution, and is far from the only solution. I'm just going to use hard-coded string examples instead of message.content, to allow this to be in a working snippet:
//Our array of bad words
var badWords = [
'bannedWord1',
'bannedWord2',
'bannedWord3',
'bannedWord4'
];
//A function that tests if a given string contains a bad word
function testProfanity(string) {
//Removes all non-letter, non-digit, and non-space chars
var normalString = string.replace(/[^a-zA-Z0-9 ]/g, "");
//Replaces all non-letter, non-digit chars with spaces
var spacerString = string.replace(/[^a-zA-Z0-9]/g, " ");
//Checks if a condition is true for at least one element in badWords
return badWords.some(swear => {
//Removes any non-letter, non-digit chars from the bad word (for normal)
var filtered = swear.replace(/\W/g, "");
//Splits the bad word into a 's p a c e d' word (for spaced)
var spaced = filtered.split("").join(" ");
//Two different regexes for normal and spaced bad word checks
var checks = {
spaced: new RegExp(`\\b${spaced}\\b`, "gi"),
normal: new RegExp(`\\b${filtered}\\b`, "gi")
};
//If the normal or spaced checks are true in the string, return true
//so that '.some()' will return true for satisfying the condition
return spacerString.match(checks.spaced) || normalString.match(checks.normal);
});
}
var result;
//Includes one banned word; expected result: true
var test1 = "I am a bannedWord1";
result = testProfanity(test1);
console.log(result);
//Includes one banned word; expected result: true
var test2 = "I am a b a N_N e d w o r d 2";
result = testProfanity(test2);
console.log(result);
//Includes one banned word; expected result: true
var test3 = "A bann_eD%word4, I am";
result = testProfanity(test3);
console.log(result);
//Includes no banned words; expected result: false
var test4 = "No banned words here";
result = testProfanity(test4);
console.log(result);
//This is a tricky one. 'bannedWord2' is technically present in this string,
//but is 'bannedWord22' really the same? This prevents something like
//"wash it" from being labeled a bad word; expected result: false
var test5 = "Banned word 22 isn't technically on the list of bad words...";
result = testProfanity(test5);
console.log(result);
I've commented each line thoroughly, such that you understand what I am doing in each line. And here it is again, without the comments or testing parts:
var badWords = [
'bannedWord1',
'bannedWord2',
'bannedWord3',
'bannedWord4'
];
function testProfanity(string) {
var normalString = string.replace(/[^a-zA-Z0-9 ]/g, "");
var spacerString = string.replace(/[^a-zA-Z0-9]/g, " ");
return badWords.some(swear => {
var filtered = swear.replace(/\W/g, "");
var spaced = filtered.split("").join(" ");
var checks = {
spaced: new RegExp(`\\b${spaced}\\b`, "gi"),
normal: new RegExp(`\\b${filtered}\\b`, "gi")
};
return spacerString.match(checks.spaced) || normalString.match(checks.normal);
});
}
Explanation
As you can see, this filter is able to deal with all sorts of punctuation, capitalization, and even single spaces/symbols in between the letters of a bad word. However, note that in order to avoid the "wash it" scenario I described (potentially resulting in the unintentional deletion of a clean message), I made it so that something like "bannedWord22" would not be treated the same as "bannedWord2". If you want it to do the opposite (therefore treating "bannedWord22" the same as "bannedWord2"), you must remove both of the \\b phrases in the normal check's regex.
I will also explain the regex, such that you fully understand what is going on here:
[^a-zA-Z0-9 ] means "select any character not in the ranges of a-z, A-Z, 0-9, or space" (meaning all characters not in those specified ranges will be replaced with an empty string, essentially removing them from the string).
\W means "select any character that is not a word character", where "word character" refers to the characters in ranges a-z, A-Z, 0-9, and underscore.
\b means "word boundary", essentially indicating when a word starts or stops. This includes spaces, the beginning of a line, and the end of a line. \b is escaped with an additional \ (to become \\b) in order to prevent javascript from confusing the regex token with strings' escape sequences.
The flags g and i used in both of the regex checks indicate "global" and "case-insensitive", respectively.
Of course, to get this working with your discord bot, all you have to do in your message handler is something like this (and be sure to replace badWords with your filter variable in testProfanity()):
if (testProfanity(message.content)) return message.delete();
If you want to learn more about regex, or if you want to mess around with it and/or test it out, this is a great resource for doing so.

JavaScript RegEx double name

I want to only allow one capital letter at start, and one more if(after hyphen) and that your able to write only one hyphen, so that u can write a double name, like Klas-Bertil and nothing else.
Shall allow:
Klas
Klas-Bertil
Fredrick-Patrick
not:
KlAs-
KLaS-bErtIl
Fre-Dr-IckP-aTrick
Dont know if im making myself understood? :)
Thanks in advance!
try this:
^[A-Z]?[a-z]*(?:-[A-Z][a-z]*)?$
if you'd like to force capital letter at the start:
^[A-Z][a-z]*(?:-[A-Z][a-z]*)?$
Have the simplest RegEx for the name parts, like this
var regEx = /^[A-Z][a-z]*$/;
This will match any string which starts with zero or more white space characters, followed by a capital letter, followed by a string of small letters and ends with zero or more characters.
Now, split the input string with - and apply the regEx on all of them to see if all the parts match or not.
var regEx = /^[A-Z][a-z]*$/;
function isInitCapNames(name) {
return name.split("-").every(function(currentPart) {
return regEx.test(currentPart);
});
}
Test cases:
console.assert(isInitCapNames('Klas') === true);
console.assert(isInitCapNames('Klas-Bertil') === true);
console.assert(isInitCapNames('Fredrick-Patrick') === true);
console.assert(isInitCapNames('KlAs-') === false);
console.assert(isInitCapNames('KLaS-bErtIl') === false);
console.assert(isInitCapNames('Fre-Dr-IckP-aTrick') === false);
I hope this will work for you.
/^([A-Z]{1,1})([a-z]+)-([A-Z]{1,1})([a-z])$/
How about instead of restricting the users, just fix their input? would be much more convenient for both sides i believe:
var names = ["KlAs-","KLaS-bE$#rtIl-banana","Fre-Dr-IckP-aTrick","Klas","Klas-Bertil","Fredrick-Patrick"]
function FixName(name){
//remove all special characters from the name
name = name.replace(/[^a-zA-Z0-9_-]/g,'');
//check for hyphens and only get 1 of those, takes 2 name parts.
var name_parts = name.split('-',2);
//fix the first name part
var Fixed_Name=(name_parts[0].charAt(0).toUpperCase() + name_parts[0].slice(1).toLowerCase()).trim();
//check if there is anything after the hyphen, and fix it too.
if(name_parts[1].trim()!=""){
Fixed_Name+="-"+(name_parts[1].charAt(0).toUpperCase() + name_parts[1].slice(1).toLowerCase()).trim();
}
alert(Fixed_Name);
}
FixName(names[1]);

JavaScript split string around emails

So I have this list of emails:
john.doe#doe.com
john.doe#doe.com
john.doe#doe.com
john.doe#doe.com
john.doe#doe.com
john.doe#doe.com
john.doe#doe.com
john.doe#doe.com
It comes through as a string, sometimes with a return character at the end of each line, sometimes it doesn't. All I want to be able to do is pull out each email from the string using regex.
So I've got this regex exp from here:
function validateEmail(email) {
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
How do I get it to match many email addresses and return me each individual email?
I do not want to split on a return character, I can't always garauntee that it will be that character that will split the list up. These emails are pasted in from the users clipboard. If it were that easy, I wouldn't have asked ;)
It comes through as a string, with a return character at the end of
each line.
Then just split the string on newlines ?
var email_array = str.split("\n");
Here's a VERY simple way to do it.
/([^;:<>!?\n]+\#[^;:<>!?\n]+\.[^;:<>!?\n]+)/gmi
Explanation:
The [^;:<>!?\n] matches everything EXCEPT those characters. So [^;:<>!?\n]+ just means match everything but these as many times as needed.
Then match an # symbol.
Then match as many of NOT these ([^;:<>!?\n]) as needed again.
Then match a literal dot (.).
Then DON'T match these ([^;:<>!?\n]) again.
The gmis at the end are called flags. They mean:
g means global. Match this RegEx over and over.
m means multi-line. Don't stop at the end of the first line of emails.
i means insensitive. Don't worry about the upper and lower cases.
Demonstrations here: https://regex101.com/r/aC5cK2/1
So I have re work the answer to incorporate what #adeneo said:
$scope.pasteThis = function(e) {
var emails = e.clipboardData.getData('text/plain');
var emailArray = emails.split(/(\n|\s|,)/);
angular.forEach(emailArray, function (e) {
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+#[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
if (EMAIL_REGEXP.test(e)) {
if (!contains($scope.emailAddresses, e)) {
$scope.emailAddresses.push(e);
}
}
});
}
function contains(arr, el) {
var found = false;
angular.forEach(arr, function(e) {
if (e == el) {
found = true;
}
});
return found;
}
So EMAIL_REGEXP is from the Angular source code. I use that in other places so it is very appropriate to use it here (consistency).
This function makes sure that after the emails are split, each one is a valid email address. This means that no mess can get through.

alphanumeric regex javascript

I am having a problem to get the simple reges for alphanumeric chars only work in javascript :
var validateCustomArea = function () {
cString = customArea.val();
var patt=/[0-9a-zA-Z]/;
if(patt.test(cString)){
console.log("valid");
}else{
console.log("invalid");
}
}
I am checking the text field value after keyup events from jquery but the results are not expected, I only want alphanumeric charachters to be in the string
This regex:
/[0-9a-zA-Z]/
will match any string that contains at least one alphanumeric character. I think you're looking for this:
/^[0-9a-zA-Z]+$/
/^[0-9a-zA-Z]*$/ /* If you want to allow "empty" through */
Or possibly this:
var string = $.trim(customArea.val());
var patt = /[^0-9a-z]/i;
if(patt.test(string))
console.log('invalid');
else
console.log('valid');
Your function only checks one character (/[0-9a-zA-Z]/ means one character within any of the ranges 0-9, a-z, or A-Z), but reads in the whole input field text. You would need to either loop this or check all characters in the string by saying something like /^[0-9a-zA-Z]*$/. I suggest the latter.
I fixed it this way
var validateCustomArea = function () {
cString = customArea.val();
console.log(cString)
var patt=/[^0-9a-zA-Z]/
if(!cString.match(patt)){
console.log("valid");
}else{
console.log("invalid");
}
}
I needed to negate the regex

Categories