Before everything, I have been making a word filter program for my discord.js bot so excuse me for the bad words!
Since you can't add extra parameters in includes() I decided to make a var line:
var filteredwords = ['asshole', 'fuck']
But now I want to place these words (further more will be added) in the following code line:
if (message.content.includes('asshole'));
So instead of 'asshole' I want to place the array? How can I do that? Since I'm a beginner in JS I could not understand the other topics with a similar question. It would be fine if you explain it in noob language. :)
If useful, this is my full code:
const Discord = require('discord.js');
const client = new Discord.Client();
var filteredwords = ['asshole', 'fuck']
function commandIs(str, msg) {
return msg.content.toLowerCase().startsWith('--' + str);
}
client.on('ready', () => {
console.log('The bot is started succesfully')
});
client.on('message', message => {
if (commandIs('trump', message)) {
message.reply('He is the president of the United States of America!');
}
if (commandIs('putin', message)) {
message.reply('He is the president of Russia!');
}
if (commandIs('spacetaco', message)) {
message.reply('He is the first user who joined Arcanews!');
}
if (message.content.includes('asshole')); {
message.reply('Do not swear please');
message.delete();
var colors = require('colors/safe');
console.log(colors.red(`The following message got deleted:
${message.content}`));
}
});
if(filterwords.some(badword=>message.content.includes(badword))){
alert("BAD!");
}
Array.prototype.some iterates over the array and returns true if one of the given function called with the array elem as argument is true, therefore if it contains at least one bad word...
Because of the "includes" method you used, I think the type of "message.content" is an array.
Therefore, the problem can be regard as compare two arrays. You can simply apply two loops for checking, or you can use reduce method for checking.
var messageA = {
content: "Here is a asshole in it.".split(" "),
};
var messageB = {
content: "Here is a hole in it.".split(" "),
};
var filteredwords = ['asshole', 'fuck'];
var isValidA = messageA.content.reduce(function(pre, cur) {
if (pre) return !!filteredwords.indexOf(cur);
return pre;
}, true);
var isValidB = messageB.content.reduce(function(pre, cur) {
if (pre) return !!filteredwords.indexOf(cur);
return pre;
}, true);
console.log(isValidA); // false
console.log(isValidB); // true
You can use regex matching here. A much faster implementation
var filteredwords = ['bad-word', 'another-bad-word']
var message = 'Hello this string has a bad-word in it'; // Use your messsage.content here
// In a regex - '\b' start or end of a word
// " .join('\\b|\\b') " - gives me a regex string with each of the values from filteredwords array concatinated to for a 'OR' expression
// Here is th regex exp taht is generated `\basshole\b|\bfuck\b`
if( (new RegExp( '\\b' + filteredwords.join('\\b|\\b') + '\\b') ).test(message) ){
alert('match'); // Here the word were matched
}else{
alert('no match'); // Wooho, a safe message
}
Pro tip :
RegEx solution stands out in a way that you do the match that are case-insensitive and for bad-words that appear as a part of another word eg 'dambad-Word' would give a match for bad-word
EDIT: Updating answer to the full-code posted by const Discord = require('discord.js');
const client = new Discord.Client();
var filteredwords = ['asshole', 'fuck']
function commandIs(str, msg) {
return msg.content.toLowerCase().startsWith('--' + str);
}
client.on('ready', () => {
console.log('The bot is started succesfully')
});
client.on('message', message => {
if (commandIs('trump', message)) {
message.reply('He is the president of the United States of America!');
}
if (commandIs('putin', message)) {
message.reply('He is the president of Russia!');
}
if (commandIs('spacetaco', message)) {
message.reply('He is the first user who joined Arcanews!');
}
if ( (new RegExp('\\b' + filteredwords.join('\\b|\\b') + '\\b')).test(message.content ) ) {
message.reply('Do not swear please');
message.delete();
var colors = require('colors/safe');
console.log(colors.red(`The following message got deleted:${message.content}`));
}
});
If you want to do the matching for not whole words like say curseWord should be detected in the sentence hello there youcurseword (case insensitive as well), you can replace the last IF condition with :
// We can get rid of '\b' to make the search not limited to whole-word matching
if ((new RegExp(filteredwords.join('|'))).test(message.content))
// We can use 'i' flag to make the matching case insensitive
if ((new RegExp(filteredwords.join('|') , 'i')).test(message.content))
Related
I'm trying to make a irc bot that takes input like this user: +1 I want to have a end result where I can have a main number being added to, from the # someone types with +#.
expected output: #x added: 1 rep: 1 executed[+] second execution
#x added: 1 rep: 2 executed[+]
actual output #x added: +1 rep: +1undefined executed[+] second is identical.
I've tried using Number(commandName), along with toString().replace(/\D\s/g,'') I got some promising results but they seemed to have some problems so I scrapped that code...
so in conclusion how can I add the numbers together and avoid the +?
const tmi = require('tmi.js');
// Define configuration options
const opts = {
identity: {
username: "x",
password: "x"
},
channels: [
"#x"
]
};
// Create a client with our options
const client = new tmi.client(opts);
// Register our event handlers (defined below)
client.on('message', onMessageHandler);
client.on('connected', onConnectedHandler);
// Connect to Twitch:
client.connect();
const totalnum = 0;
// Called every time a message comes in
function onMessageHandler(target, context, msg, self) {
if (self) {
return;
} // Ignore messages from the bot
// Remove whitespace from chat message
let commandName = msg.trim();
var regexadd = /([+]\d*)[^+\s]/;
// If the command is known, let's execute it
if (regexadd.exec(commandName)) {
var totalnum = addem(commandName, totalnum);
console.log(target, `added:`, commandName, `rep:`, totalnum, `executed[+]`)
} else {
console.log(`* Unknown command ${commandName}`);
}
function addem(x, y) {
return (x + y);
}
}
// Called every time the bot connects to Twitch chat
function onConnectedHandler(addr, port) {
console.log(`* Connected to ${addr}:${port}`);
}
I found a few things that appear to be wrong with your code:
You're not adding numbers. addem()'s first parameter is the name of the command, it should be the number captured in your regex capture group.
Your regex includes the + sign in the capture group, you probably wanted to exclude it
You should parse the result of exec to a hint either with ParseInt() or implicitly with +
You use RegExp.prototype.exec() instead of RegExp.prototype.match() to retrieve a capture group.
Here's what this could look like
var regexadd = /\+(\d*)[^+\s]/;
if (regexadd.exec(commandName)) {
var totalnum = addem(+commandName.match(regexadd)[1], totalnum);
console.log(target, `added:`, commandName, `rep:`, totalnum, `executed[+]`)
}
I also think it would be best to use RegExp.prototype.test() instead of RegExp.prototype.exec() for your if statement - you will limit results to true or false.
I have a JavaScript code that gets the lyrics of a song that is currently playing through an API.
Sometimes (not always) the lyric returns the title at the beginning which is what I want to remove.
Sometimes the title at the beginning is in uppercase, other times in uppercase and lowercase.
Example:
SWEET CHILD O' MINE
She's got a smile that it seems to me
Reminds me of childhood memories
Where everything was as fresh as the bright blue sky
Now and then when I see her face
She takes me away to that special place
And if I stare too long, I'd probably break down and cry
........
I have created a somewhat cumbersome code that removes the title from the beginning with success.
I want to see if they help me simplify that code in fewer lines.
I will share the part of the code that interests us to facilitate the help, if you want all the code I have no problem sharing it.
currentSong contains the title of the song that is playing
lyric contains full lyric obtained with the API
this.refreshLyric = function(currentSong, currentArtist) {
//another code that does not interest
//...
//...
//lyric variable contains the complete lyrics of a song obtained through an API
var lyric = data.mus[0].text;
//divide the string CurrentSong (contains the song title) into parts
let splitCurrenSong = currentSong.split(' ');
//I get the length of the array
let largeCurrentSong = splitCurrenSong.length;
//divide the string lyric into parts
let splitLyric = lyric.split(' ');
//I get the first elements of the lyric array with the length limit of largeCurrentSong
let pieceLyric = splitLyric.slice(0, largeCurrentSong);
//I get all elements of the splitCurrenSong array
let pieceSong = splitCurrenSong.slice(0, largeCurrentSong);
//join arrays
let joinLyric = pieceLyric.join(' ');
let joinSong = pieceSong.join(' ');
//I check if the chunk of the joinLyric string matches the same chunk of joinSong
if (joinLyric.toLocaleLowerCase() == joinSong.toLocaleLowerCase()) {
//remove the matching items
splitLyric.splice(0, largeCurrentSong);
//put the resulting join array into a variable
lyrics = splitLyric.join(' ');
//remove the spaces from the beginning and end of lyrics
lyric = lyrics.trim()
}
//another code that does not interest
//...
//...
}
EDIT: to reply to #iamaword
As shown in the screenshot of the API return:
text: contains the lyrics of the complete song
name: song title
I can perfectly get the name of the song with this line:
var nameSong = data.mus[0].name
But I don't think it's necessary since I get the name of the song from the currentSong variable, which is the one sent in the GET command to get the lyric.
FINAL EDIT: credits to #CerebralFart
full code:
this.refreshLyric = function(currentSong, currentArtist) {
var proxy_URL = PROXYURL;
var vagalume_api = 'https://api.vagalume.com.br/search.php?';
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
var data = JSON.parse(this.responseText);
if (data.type === 'exact' || data.type === 'aprox') {
var lyric = normalizeText(data);
document.getElementById('lyric').innerHTML = lyric.replace(/\n/g, '<br />');
var openLyric = document.getElementsByClassName('lyrics')[0];
openLyric.style.opacity = "1";
openLyric.setAttribute('data-toggle', 'modal');
var powered = "Vagalume"
var URL_lyric = 'https://www.vagalume.com.br';
//Powered by image src...
const parent = document.querySelector('.chartlyrics');
parent.innerHTML = '';
var img = document.createElement("img");
img.src = "img/103-fundo-escuro.jpg"
img.setAttribute('class', "")
parent.appendChild(img);
parent.appendChild(document.createElement('br'));
parent.append('Powered by ');
// Powered by link a href...
document.getElementById('powered_by').innerHTML = ''
var a = document.getElementById('powered_by')
.appendChild(document.createElement("a"));
a.href = URL_lyric;
a.target = "_blank";
a.rel = "noopener noreferrer";
a.textContent = powered;
} else {
var page = new Page();
page.refreshLyric2(currentSong, currentArtist);
}
} else {
var page = new Page();
page.refreshLyric2(currentSong, currentArtist);
}
}
}
xhttp.open('GET', proxy_URL + vagalume_api + API_KEY + '&art=' + currentArtist + '&mus=' + currentSong.toLowerCase(), true);
xhttp.send()
}
function normalizeText(response){
// First unpack the data, get the right name and text values
let {mus:[{name, text}]} = response;
// Now get the part of the text that might be the title
let titleLength = name.length;
let maybeTitle = text.substring(0, titleLength);
// Compare the two titles and trim if they match
if (name.toLowerCase() === maybeTitle.toLowerCase() && exceptions.includes(maybeTitle.toLowerCase()) == false){
text = text.substring(titleLength)
}
//Remove any leading or trailing whitespace and return
return text.trim();
}
//song names excepted from being removed in lowercase ['one song', 'two song', etc..]
const exceptions = ['sweet emotion'];
I have created a list of song names excepted from being removed, in case any of them mention the song title as part of the lyric.
This is the case for example of the well-known Aerosmith - Sweet Emotion song.
Sweet emotion
Sweet emotion
You talk about things and nobody cares
You're wearing other things that nobody wears
You're calling my name but you gotta make clear
I can't say baby where I'll be in a year
.....
I added a new condition to the normalizeText function to check if the name of the song to be removed is not within the exceptions.
// Compare the two titles and trim if they match
if (name.toLowerCase() === maybeTitle.toLowerCase() && exceptions.includes(maybeTitle.toLowerCase()) == false){
And I created a constant exceptions where the name of the songs in lowercase must be added manually separated by commas.
//song names excepted from being removed in lowercase ['one song', 'two song', etc..]
const exceptions = ['sweet emotion'];
There are a few ways in which your code can be cleaned up, mainly in how you unpack the data and in how you compare the two strings.
function normalizeText(response){
// First unpack the data, get the right name and text values
let {mus:[{name, text}]} = response;
// Now get the part of the text that might be the title
let titleLength = name.length;
let maybeTitle = text.substring(0, titleLength);
// Compare the two titles and trim if they match
if (name.toLowerCase() === maybeTitle.toLowerCase()){
text = text.substring(titleLength)
}
//Remove any leading or trailing whitespace and return
return text.trim();
}
EDIT: sintax error toLowerCase added ()
I'm currently making a chatbox in JQuery. I've been using indexOf but I think it might be more efficient to use regExp.
my current code is
function ai(message){
if (username.length<3){
username = message;
send_message("Nice, to meet you " + username + ", how are you doing?");
}
if(message.indexOf("how are you?")>=0) {
send_message("I'm feeling great!");
}
if(message.indexOf("weather")>=0 ){
send_message("In England it is shitty");
}
var n = message.search(/\b(cat|cats|kitten|feline)\b/i);
if (n !== -1) {
send_message("i hate cats");
}
else {
for (i=0; i <= botChat.length; i++) {
var re = new RegExp (botChat[i][0], 'i');
if (re.test(message)) {
var length = botChat[i].length - 1;
var index = Math.ceil( length * Math.random());
var reply = (botChat[i][index]);
send_message(reply);
}
}
}
}
and a typical line from my array is
new Array ("I need (.*)\." , "Why do you need $1?", "Would it really help you to get $1?" , "Are you sure you need $1?"),
i'm trying to demonstrate the ways of creating a chatbot. The first four responses work perfectly
it takes a name, comments on the weather and can search for cats. What it can't do is perform the loop. Has anyone any suggestions?
I tried to validate url with or without http No matter what i did the function return false.
I checked my regex string in this site:
http://regexr.com/
And its seen as i expect.
function isUrlValid(userInput) {
var regexQuery = "/(http(s)?://.)?(www\.)?[-a-zA-Z0-9#:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9#:%_\+.~#?&//=]*)/";
var url = new RegExp(regexQuery,"g");
if (url.test(userInput)) {
alert('Great, you entered an E-Mail-address');
return true;
}
return false;
}
I fix the problem by change the .test to .match and leave the regex as is.
I change the function to Match + make a change here with the slashes and its work: (http(s)?://.)
The fixed function:
function isUrlValid(userInput) {
var res = userInput.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9#:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9#:%_\+.~#?&//=]*)/g);
if(res == null)
return false;
else
return true;
}
I believe the other answer will reject some valid url's (like domain names in uppercase or long sub-domains) and allow some invalid ones (like http://www.-example-.com or www.%#&.com). I tried to take into account a number of additional url syntax rules (without getting into internationalisation).
function isUrlValid(userInput) {
var regexQuery = "^(https?://)?(www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6}(/[-\\w#\\+\\.~#\\?&/=%]*)?$";
var url = new RegExp(regexQuery,"i");
return url.test(userInput);
}
var input = ["https://o.sub-domain.example.com/foo/bar?foo=bar&boo=far#a%20b",
"HTTP://EX-AMPLE.COM",
"example.c",
"example-.com"];
for (var i in input) document.write(isUrlValid(input[i]) + ": " + input[i] + "<br>");
To also allow IP addresses and port numbers, the regex is:
"^(https?://)?(((www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6})|((\\d{1,3}\\.){3}\\d{1,3}))(:\\d{2,4})?(/[-\\w#\\+\\.~#\\?&/=%]*)?$"
To also allow query strings without a slash between the domain name and the question mark (which is theoretically not allowed, but works in most real-life situations), the regex is:
"^(https?://)?(((www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6})|((\\d{1,3}\\.){3}\\d{1,3}))(:\\d{2,4})?((/|\\?)[-\\w#\\+\\.~#\\?&/=%]*)?$"
To also make sure that every % is followed by a hex number, the regex is:
"^(https?://)?(((www\\.)?([-a-z0-9]{1,63}\\.)*?[a-z0-9][-a-z0-9]{0,61}[a-z0-9]\\.[a-z]{2,6})|((\\d{1,3}\\.){3}\\d{1,3}))(:\\d{2,4})?((/|\\?)(((%[0-9a-f]{2})|[-\\w#\\+\\.~#\\?&/=])*))?$"
(Note: as John Wu mentioned in a comment, there are valid single-letter domains).
Actually, this question needs a powerful regex and the following code is not very hard to understand, please see below(ES6 - TypeScript):
const isValidUrl = (url: string): boolean => {
const urlRegex = /^((http(s?)?):\/\/)?([wW]{3}\.)?[a-zA-Z0-9\-.]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?$/g;
const result = url.match(urlRegex);
return result !== null;
};
Try this code.
function CheckURL(fieldId, alertMessage) {
var url = fieldId.value;
if(url !== "")
{
if (url.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9#:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9#:%_\+.~#?&//=]*)/g) !== null)
return true;
else {
alert(alertMessage);
fieldId.focus();
return false;
}
}
}
var website = document.getElementById('Website');
if (!CheckURL(website, "Enter a valid website address")) {
return false;
}
I want to validate input as I type so I use onkeyup event to do so, but if I validate an email regex "name#domain.com", as soon as user starts to type it throws an error - first character doesnt match regex...
So I wrote this:
var addValidation = function (patterns) {
var index = patterns.length; //I know I can avoid this
while (index--) {
patterns[index] = new RegExp(patterns[index]);
}
index = 0;
var current = patterns[index],
matchExact = function (patt, str) {
var match = str.match(patt);
return match !== null && str === match[0];
};
return function () {
var str = this.value;
if (!matchExact(current, str) ) {
var tmp = patterns[index + 1] ?
new RegExp(current.source + patterns[index + 1].source) :
false;
if (tmp && matchExact(tmp, str)) {
current = tmp;
index++;
}
else {
alert("Wrong");
}
}
}
};
document.getElementById("x").onkeyup = addValidation(["[a-zA-Z0-9\\.]+", "#{1}", "[a-zA-Z0-9]+", "\\.{1}", "[a-zA-Z]{1,3}"]);
It seems to work, but... it's ugly and it will alert you if you do step back (eg. "name#" and you press backspace).
I know that Dojo's validation is great, but I do not want to use Dojo. Are there any better ways to achieve that?
//EDIT: http://livedocs.dojotoolkit.org/dijit/form/ValidationTextBox this is an example, but you can define your own pattern (like email regex) and it will validate it perfectly.
Add interval before validation will start:
var t;
document.getElementById("x").onkeyup = function () {
if (t) {
clearTimeout(t);
}
t = setTimeout(function () {
//do validation
}, 1000)
}
Don't ever try to validate an email address with a regualr expression. You'll either end up allowing addresses which are not valid, or block email addresses which are perfectly valid and just annoy your visitors. It's also worth bearing in mind that the best regex so far for validating email addresses is this:
http://www.ex-parrot.com/pdw/Mail-RFC822-Address.html