I'm working in JavaScript with discord.js#v12. I asked this question in their support Discord, but due to issue in question being more related to JavaScript than Discordjs, here I am!
Let's get on it. I would like to fill out a RichEmbed in one single message. This RichEmbed will include a title, a description and 1 field. There can be more than one field in RichEmbeds, so I want to get it clear I only need 1.
Now, I realize I could do this using the following ways a) using awaitMessages and filling in the info one message at a time b) Separating arguments in the message with a space and making each argument text-like-this c) Separating arguments in the message with a newline and making each line a full argument. However, neither of these look very appealing to me. I also have a few people who are going to use my command who are not very technical and thus may not understand the usage of the command unless having a very detailed explanation, which is not very efficient when I'm not available.
I've used a) in the past and it's proven rather unefficient in a fast workflow, and b is straight up useless if I require a long description with a lot of sentences. C is usable but, again, there will be people using this command who are not technically "capable" and thus may struggle on their own. I want to make this as fluent as I can.
I also tried this method, which I found fairly useful but can be confusing:
/commandname Separating title / Description and / Field by a forward slash
So I came to the conclusion I want my syntax looking something like this:
/commandname title:My title! desc:This is the description field1:Field 1 and its title
EDIT: I spent a bit of research after posting, and found out I can use replace method to get the above result. This is currently my code:
let embed_title
let embed_desc
let embed_field
let firstarg = args[1]
if (firstarg.includes(`title:`)) {
var split = firstarg.replace(`title:`, ``)
embed_title = split
// expected output with "/commandname title:Testing123!": /commandname Testing123!
} else if (firstarg.includes(`desc:`)) {
var split = firstarg.replace(`desc:`, ``)
embed_desc = split
// expected output with "/commandname desc:Testing123!": /commandname Testing123!
} else if (firstarg.includes(`field:`)) {
var split = firstarg.replace(`field:`, ``)
embed_field = split
// expected output with "/commandname field:Testing123!": /commandname Testing123!
}
With this I can easily replace the first argument that has title:, desc: or field: in it, however I'd like to scour through the whole message (message.content). After that, I want to find which argument has title: in it. Then I want to feed every argument after title until it hits desc:. Repeat that until field is covered.
I solved my question by using a different syntax.
Instead of using /command and then:
title:Title of message desc:Description of message field1:Field of message
I'm using /command and then:
title Title of new message
description Description of new message
field Field 1 of new message
I'm splitting the arguments by newline \n instead of space/whitespace.
const msgArray = message.content.split(/ +/g)
const args = message.content.slice(prefix.length + msgArray[0].length).trim().split(`\n`)
Since I'm splitting the arguments by newline, it allows me to use spaces in my arguments without worrying about them coming out weird.
I then check for each argument and if it begins with Title, Description or Field, or none of them. Then, I iterate through each argument (from 1 to 3 in human terms) and check if they start with any of the three, then go from there. Note that this is manual and does not have superb compatibility if I wish to add another field or an image, but this works for my case and thus, I've solved it for now.
I realized this afternoon that I can simply loop through all the args and find which one contains a certain keyword. In the process, I can also filter out anything that does not match certain keyword(s).
Complete code as follows:
var _title = ``
var _desc = ``
var _fieldvalue = ``
var _useless = ``
args.forEach((element, i) => {
i += 1
if (element.startsWith(`description `)) {
_desc = element.slice(12)
}else if (element.startsWith(`title `)) {
_title = element.slice(6)
}else if (element.startsWith(`field `)) {
_fieldvalue = element.slice(6)
}else{
_useless = element
}
})
if (!_title && !_desc) return message.channel.send(`Please include at least a title or a description by using \`title\` or \`description\`.`)
if (!_fieldvalue) {
message.channel.send({embed: {
title: _title || null,
description: _desc || null,
}})
} else {
message.channel.send({embed: {
title: _title || null,
description: _desc || null,
fields: [
{
name: `\u200b`,
value: _fieldvalue,
},
],
}})
}
For those of you who want to see the code for the original result, see this pastebin result.
Related
I've been asked to optimize the speed of my query. I currently have this regex in my query, which is checking for a pattern and returning substring within that pattern. To clarify I have a table with multiple columns that I have to look through to check for this value: [v= and return the numbers within that list.
This is looking through several 'name..' columns that look something like this: xyzzy [v=123] but I only want to return 123, the below works:
COALESCE(REGEXP_SUBSTR(NAME, '[[]v=([0-9]+)', 1, 1, 'ie'),
REGEXP_SUBSTR(NAME_5, '[[]v=([0-9]+)', 1, 1, 'ie'),
REGEXP_SUBSTR(NAME_4, '[[]v=([0-9]+)', 1, 1, 'ie')) as display_vertical_code
but to optimize this, I thought of maybe creating a function unfortunately I don't know javascript :/ and I don't know if the formatting is correct I'm having some difficulties creating it, this is what I've tried, can someone tell me if I'm missing something?
CREATE OR REPLACE FUNCTION dfp.regex(NAME VARCHAR)
RETURNS OBJECT
LANGUAGE javascript
STRICT AS '
return new RegExp(NAME,"[[]v=([0-9]+)",1 ,1,"ie")
';
When I try to use the above function in my below query:
COALESCE(
GET(DFP.REGEX(NAME)),
GET(DFP.REGEX(NAME_5)),
GET(DFP.REGEX(NAME_4)),
GET(DFP.REGEX(NAME_3)),
GET(DFP.REGEX(NAME_2)),
GET(DFP.REGEX(NAME_1)),
GET(DFP.REGEX(NAME_0))
) as display_vertical_code
I see this error:
error line 3 at position 8 not enough arguments for function
[GET(REGEX(Tablename.NAME))], expected 2, got 1
This should do it.
CREATE OR REPLACE FUNCTION regex(NAME VARCHAR)
RETURNS string
LANGUAGE javascript
STRICT IMMUTABLE AS
$$
const regex = /[[]\s{0,5}v\s{0,5}=\s{0,5}([0-9]+)/i;
let s = NAME.match(regex);
if (s != null) {
return s[0].split('=')[1].trim();
} else {
return null;
}
$$;
select regex('xyzzy [v=123]');
-- Alternate permutation
select regex('xyzzy [ v = 123]');
You want to return a string, not an object. Adding the IMMUTABLE option tells Snowflake that the same input results in the same output every time. It can sometimes help with performance.
Edit... This one's a bit more fault tolerant and allows whitespace (if that could be a problem). If you want to get rid of allowing whitespace, delete the \s{0,5} expressions.
Currently I am using the following to evaluate variables that are placed in strings at runtime:
newVal = eval("`" + newVal + "`");
So if I have the string:
"Hello from channel: ${erpVars["CommandChannel"]["name"]}"
And erpVars["CommandChannel"]["name"] has value home, then the resulting string is:
Hello from channel: home
There are other objects than just erpVars that could be holding matching values for the string, but this is just one example. It's also important to note that each string could have more than one variable that needs replacing.
I am trying to achieve the same thing without using eval(), as some of the variable values come from user input.
Your case sounds super nasty (you should never ever use eval in JS! It poses a major security threat! also it looks weird that you want to replace this sort of a string) and perhaps if you told me more about where you get your inputs from and in what form, then maybe we could find together a much better solution for this. On that note, this is how I would solve your issue in its current form.
const newVal = 'Hello from channel: ${erpVars["CommandChannel"]["name"]}';
const strings = {
erpVars: {
CommandChannel: {
name: "home"
}
}
};
const vars = newVal.match(/\$\{.+?\}/g);
let result = newVal;
vars.forEach(v => {
let valuePath = '${erpVars["CommandChannel"]["name"]}'.match(/[\w\d]+/g).join('.');
result = result.replace(v, _.get(strings, valuePath));
});
console.log(result);
Note that I'm skipping here the edge scenarios, like getting a null result from the newVal.match when there are no variables in the newVal, but that's easy to handle.
Also note that over here i'm using the lodash library in _.get() (https://lodash.com/docs/4.17.15#get). It's super popular for this kind of small tasks. Of course there are really a lot of other tools that allow you to extract a value based on a property path like erpVars.CommandChannel.name that is stored in the valuePath variable, including a crazy amount of instructions that tell you how to do it yourself.
I was tasked with a project of creating a CV site were the user uploads a .docx file and the details is extracted from the file and is automatically inputted in the template designed by me,
I have been able to extract the details .docx file with JavaScript and the extracted details was kept in an array to make it easy to identify words with indexing. For example
[Adeola Emmanuel, adeolaemmanuel#gmail.com, pharmacist, 2 ketu ikorodu lagos, etc].
where i need help is not all CV uploaded by the user has the name coming first or email coming second but its sure that they come within 0,6 of the array so i decided to write a function that will help with that but its not working
var email = email(text.slice(0, 5));
function email(email) {
var re = /.{1,}#[^.]{1,}/ig;
if (!re.test(email)) {
email = text.slice(0, 1);
return email;
} else if (re.test(email)) {
email = text.slice(3, 5);
return email;
}
}
You can use the find array method:
function getEmail(arr) {
let re = /\S#[^.\s]/;
return arr.find(str => re.test(str));
}
let text = ["Adeola Emmanuel", "adeolaemmanuel#gmail.com", "pharmacist", "2 ketu ikorodu lagos"];
let email = getEmail(text.slice(0, 5));
console.log(email);
Some remarks:
{1,} in regular expressions can be shortened to just +
You actually don't need to test for multiple occurrences with +, since you would already accept one occurrence. So that also means you would be OK with just one non-point character after the #.
Neither of the regex suffixes (ig) have any use in your regex.
The .test method should get a string as argument, not an array. So you need to pass it email[0] for example.
For a full test of whether some string is a valid email address, the regular expression would be way more complex
When an if condition is false, there is no need to test the exact opposite in the else block: by exclusion that opposite condition will always be true when it gets executed.
The slice of an array is still an array, so returning text.slice(3, 5); in the else block does not make sense. You want to return a string.
You need a loop to inspect other array elements for as long as you don't have a match and have not reached the end of the array. So some loop construct is needed. You can use for, while, or any of the array methods that do such looping. find is particular useful in this case.
Don't give your function the same name as another variable (email) as only one value can be assigned to that variable (a function, a string, or still something else). So in your case you'll lose the function definition by the var initialisation.
if (userResponseField.value.toUpperCase().includes('MY NAME IS ') === true || userResponseField.value.toUpperCase().includes('MY NAME\'S ') === true) {
What I am basically trying to do is create some sort of chatbot and it's working perfectly, it's just that it gets confused by extra whitespaces. How can I remove them during the condition check? I've looked for answers but none of them worked with the condition, they are still correct though, just not working with the way I want to do this whole thing. Note: I don't want the condition to make changes to the string/variable itself.
You could use regex:
if (userResponseField.value.match(/my\s+name(\s+i|')s/gi))
This returns true for inputs such as ' My name is '.
let predicate = str => !!str.match(/my\s+name(\s+i|')s/gi);
[
'my NaME iS ',
'my NaME\'s',
'my name s',
'my ame is',
'my nameis',
].forEach(input => console.log(input, ':', predicate(input)));
Have a look on trim :
if (
userResponseField.value.toUpperCase().trim().includes('MY NAME IS') === true ||
userResponseField.value.toUpperCase().trim().includes('MY NAME\'S') === true
) {
You can use String.prototype.trim() on both the value and the hard-coded string:
var userResponseField = {};
userResponseField.value = 'MY NAME IS';
if (userResponseField.value.toUpperCase().trim().includes('MY NAME IS '.trim()) === true || userResponseField.value.toUpperCase().trim().includes('MY NAME\'S '.trim()) === true) {
console.log("true");
}
it's me again.
I found a clever way to do this and if some of you, in the future, have this problem and have just found this thread, here is how I solved my problem:
var userResponseFieldOutput = userResponseField.value;
userResponseField.value = userResponseField.value.replace(/\s+/g, ' ');if
Since this code, along with the condition I have posted above are stored in a function, the userResponseFieldOutput is what I am going to use for outputting the user's messages in the chatbox. It remains unedited, while the userResponseField.value has its spaces removed.
For example:
chatResponse(userResponseFieldOutput, "Hi, " + userName);
Ignore the userName variable, it is part of the code that doesn't have to be shown right now. This is another function I have made, the first value is what appears in the chat on the right side, where the user's responses are shown. The string and the variable after the comma are what appears on the left side of the chat, where the chatbot's messages are shown. But as you can see, I don't use userResponseField.value. Instead, I am using userResponseFieldOutput, which will print the user's output without the extra white spaces being removed.
I hope I have been useful to all of you who are looking for a solution to this problem.
Hi I'm not that experienced in JavaScript, and I'm trying to parse commands given as full sentences. It has to be able to match the sentence to a function that will answer, and select sections that it will pass as arguments. I know that's not too clear so here's an example:
sentnce = "Show me a gift of a car"
commands = {
gif: {
pattern: "*gif of a [target]*"
action: gifMe(target)
This scenario should result in the call gifMe("a car") or even better, gimme could be called with a object containing all of the arguments specified, there may be more than just target. I have no idea how to go about coding this or searching for a method to do this. Thanks in advance.
It's not relevant (I think) but I'm using jquery and Coffeescript.
I think this is the code you are looking for. See the comment in the code for some more information about how it works.
var sentence = "Show me a gift of a car";
// specify commands
var commands = {
gif: {
pattern: /gift of a (.*).?/,
action: call
}
// you can add more commands here
}
// iterate over all commands
for(var key in commands)
{
// get settings for command
var settings = commands[key];
// apply command regex to sentence
var result = sentence.match( settings.pattern );
// if there is a match trigger the action with the word as argument
if( result && result.length > 1 )
settings.action.call(this, result[1]);
}
function call(value)
{
alert(value);
}