String replace regex invalid quantifier in js/GAS - javascript

Based on https://www.plivo.com/blog/Send-templatized-SMS-from-a-Google-spreadsheet-using-Plivo-SMS-API/ I have the following code:
function createMessage(){
data = {
"SOURCE" : "+1234567890",
"DESTINATION" : "+2345678901",
"FIRST_NAME" : "Jane",
"LAST_NAME" : "Doe",
"COUPON" : "DUMMY20",
"STORE" : "PLIVO",
"DISCOUNT" : "20",
}
template_data = "Hi , your coupon code for discount of % purchase at is "
Logger.log(data);
for (var key in data) {
Logger.log(key);
if (data.hasOwnProperty(key)) {
template_data = template_data.replace(new RegExp('+key+', 'gi'),data[key]); // error here
}
}
Logger.log(template_data);
return template_data;
}
When I run createMessage I get :
SyntaxError: Invalid quantifier +. (line 57, file "Code")
From a previous question and if I understand correctly the loop goes through each key, value pair looking for all matches of the key (g) in a case insensitive fashion (i).
I don't understand the pattern '+key+' This causes the error and my attempts to test patterns like '+SOURCE+' also give the same error, although the seem to work while testing at https://regex101.com/r/CF967t/2 .
Can someone give me an explanation of the problem

sign + usually is a repetition operator, and causes the preceding token to repeat one or more times key+ would be expressed as keykey*
You have pass only key
template_data = template_data.replace(new RegExp(key, 'gi'),data[key]);

Related

Angular split string to array

I have a String message like that :
messages = "Line 249 : Validation error, Line 287 : Validation error"
I want to split this message like this :
messages [] = [ { position: 1, message: 'Line 249 : Validation error' },
{ position: 2, message: 'Line 287 : Validation error' }]
Could you please help with this thank you.
The easiest way to turn a string into an array of objects is to first split the string using the delimiter, which in this case is the comma, so start with.
const test = "Line 249 : Validation error, Line 287 : Validation error";
const parts = test.split(",");
Then, you want to use the map array function to return an object for each part that's been split. The es6 map function has a callback that returns the piece of the array and the index in which it was found. you don't want the index, but rather an ordinal (per your example above)
Here's what i would do:
const test = "Line 249 : Validation error, Line 287 : Validation error";
const parts = test.split(",").map((text, index) => {
return {
position: index+1,
message: text.trim()
}
});
Now, the parts variable holds an array of objects that matches your required output
I think your error message can be split into an array using javascript split method.
so
messages = message.split(',')
will do the magic
But to add your position,
let messages = "Line 249 : Validation error, Line 287 : Validation error"
messages= messages.split(',').map((x,index)=>{
let obj ={}
obj.position=index+1;
obj.message = x
return obj;
});
console.log( messages )

Extract string after another string in a complicated string

I have this string -
ContactTrigger: execution of AfterInsert
caused by: System.DmlException: Update failed. First exception on row 0 with id 0032200000AYK5AAAX; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Spouse Cannot be more than 1: []
Class.ContactTriggerHelper.updateDependentData: line 309, column 1
Trigger.ContactTrigger: line 26, column 1
I need to identify if this string contains FIELD_CUSTOM_VALIDATION_EXCEPTION and I need to extract this part of the message 'Spouse Cannot be more than 1'
Which I am not able to
I tried this --
var pageErrors = saveResult.error[0].pageErrors[0].message;
console.log('pageErrors--->'+pageErrors);
var errMessage;
if(pageErrors.includes('FIELD_CUSTOM_VALIDATION_EXCEPTION')){
console.log('Inside includes');
console.log('pageErrors.indexOf("FIELD_CUSTOM_VALIDATION_EXCEPTION")-->'+pageErrors.indexOf('FIELD_CUSTOM_VALIDATION_EXCEPTION'));
console.log('pageErrors.lastIndexOf("FIELD_CUSTOM_VALIDATION_EXCEPTION")-->'+pageErrors.lastIndexOf('FIELD_CUSTOM_VALIDATION_EXCEPTION,'));
errMessage = pageErrors.substring(pageErrors.indexOf('FIELD_CUSTOM_VALIDATION_EXCEPTION'),pageErrors.lastIndexOf('FIELD_CUSTOM_VALIDATION_EXCEPTION,'));
}
You can try this
FIELD_CUSTOM_VALIDATION_EXCEPTION,\s*([^:]+)
let findValue = (str) => {
return str.match(/FIELD_CUSTOM_VALIDATION_EXCEPTION,\s*([^:]+)/i)
}
let str = `ContactTrigger: execution of AfterInsert
caused by: System.DmlException: Update failed. First exception on row 0 with id 0032200000AYK5AAAX; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Spouse Cannot be more than 1: []
Class.ContactTriggerHelper.updateDependentData: line 309, column 1 Trigger.ContactTrigger: line 26, column 1`
console.log(findValue(str))
console.log(findValue(str)[1])
let str2 = `ContactTrigger: execution of AfterInsert
caused by: System.DmlException: Update failed. First exception on row 0 with id 0032200000AYK5AAAX;
Class.ContactTriggerHelper.updateDependentData: line 309, column 1 Trigger.ContactTrigger: line 26, column 1`
console.log(findValue(str2))
You can even do something simpler and faster than regular expressions. Since you know the exact error message you need to track, you can split the error string from end of the error massage up to end of line or up to ":" character (you can also optionally trim it if you need to remove any surrounding spaces).
So:
const str = `ContactTrigger: execution of AfterInsert
caused by: System.DmlException: Update failed. First exception on row 0 with id 0032200000AYK5AAAX; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Spouse Cannot be more than 1: []
Class.ContactTriggerHelper.updateDependentData: line 309, column 1 Trigger.ContactTrigger: line 26, column 1`;
const ERR = 'FIELD_CUSTOM_VALIDATION_EXCEPTION,';
const ind = str.indexOf(ERR);
let msg = -1 < ind ? str.slice(ind+ERR.length, str.indexOf("\n",ind+ERR.length)) : null;
msg = msg ? msg.trim() : null; // optionally trim it as well
console.log(str);
console.log(msg);

Javascript, split a string in 4 pieces, and leave the rest as one big piece

I'm building a Javascript chat bot for something, and I ran into an issue:
I use string.split() to tokenize my input like this:
tokens = message.split(" ");
Now my problem is that I need 4 tokens to make the command, and 1 token to have a message.
when I do this:
!finbot msg testuser 12345 Hello sir, this is a test message
these are the tokens I get:
["!finbot", "msg", "testuser", "12345", "Hello", "sir,", "this", "is", "a", "test", "message"]
However, how can I make it that it will be like this:
["!finbot", "msg", "testuser", "12345", "Hello sir, this is a test message"]
The reason I want it like this is because the first token (token[0]) is the call, the second (token[1]) is the command, the third (token[2]) is the user, the fourth (token[3]) is the password (as it's a password protected message thing... just for fun) and the fifth (token[4]) is the actual message.
Right now, it would just send Hello because I only use the 5th token.
the reason why I can't just go like message = token[4] + token[5]; etc. is because messages are not always exactly 3 words, or not exactly 4 words etc.
I hope I gave enough information for you to help me.
If you guys know the answer (or know a better way to do this) please tell me so.
Thanks!
Use the limit parameter of String.split:
tokens = message.split(" ", 4);
From there, you just need to get the message from the string. Reusing this answer for its nthIndex() function, you can get the index of the 4th occurrence of the space character, and take whatever comes after it.
var message = message.substring(nthIndex(message, ' ', 4))
Or if you need it in your tokens array:
tokens[4] = message.substring(nthIndex(message, ' ', 4))
I would probably start by taking the string like you did, and tokenizing it:
const myInput = string.split(" "):
If you're using JS ES6, you should be able to do something like:
const [call, command, userName, password, ...messageTokens] = myInput;
const message = messageTokens.join(" ");
However, if you don't have access to the spread operator, you can do the same like this (it's just much more verbose):
const call = myInput.shift();
const command = myInput.shift();
const userName = myInput.shift();
const password = myInput.shift();
const message = myInput.join(" ");
If you need them as an array again, now you can just join those parts:
const output = [call, command, userName, password, message];
If you can use es6 you can do:
let [c1, c2, c3, c4, ...rest] = input.split (" ");
let msg = rest.join (" ");
You could revert to regexp given that you defined your format as "4 tokens of not-space separated with spaces followed by message":
function tokenize(msg) {
return (/^(\S+) (\S+) (\S+) (\S+) (.*)$/.exec(msg) || []).slice(1, 6);
}
This has the perhaps unwanted behaviour of returning an empty array if your msg does not actually match the spec. Remove the ... || [] and handle accordingly, if that's not acceptable. The amount of tokens is also fixed to 4 + the required message. For a more generic approach you could:
function tokenizer(msg, nTokens) {
var token = /(\S+)\s*/g, tokens = [], match;
while (nTokens && (match = token.exec(msg))) {
tokens.push(match[1]);
nTokens -= 1; // or nTokens--, whichever is your style
}
if (nTokens) {
// exec() returned null, could not match enough tokens
throw new Error('EOL when reading tokens');
}
tokens.push(msg.slice(token.lastIndex));
return tokens;
}
This uses the global feature of regexp objects in Javascript to test against the same string repeatedly and uses the lastIndex property to slice after the last matched token for the rest.
Given
var msg = '!finbot msg testuser 12345 Hello sir, this is a test message';
then
> tokenizer(msg, 4)
[ '!finbot',
'msg',
'testuser',
'12345',
'Hello sir, this is a test message' ]
> tokenizer(msg, 3)
[ '!finbot',
'msg',
'testuser',
'12345 Hello sir, this is a test message' ]
> tokenizer(msg, 2)
[ '!finbot',
'msg',
'testuser 12345 Hello sir, this is a test message' ]
Note that an empty string will always be appended to returned array, even if the given message string contains only tokens:
> tokenizer('asdf', 1)
[ 'asdf', '' ] // An empty "message" at the end

Parse a JS script using PHP and REGEX to get a JS variable value

I need to open a JS file from PHP, to find a json var in this file, and convert it to a php array.
Right now I can't figure out which regex to use.
// get the js file
$file = file_get_contents ("http://pve.proxmox.com/pve2-api-doc/apidoc.js");
// extract the json content of var pveapi
if ( preg_match ( "#pveapi = ({[^}]*})#", $file, $infoJson ) ) {
$arrJson = json_decode ( $infoJson [1], true );
}
// shows nothing so far :((
print_r($arrJson);
I have found few examples to do that, but none would work for me. Anyone with decent skills in regex could help me please ?
Ben
edit: added a part of the js file :
var pveapi = [
{
"info" : {
"GET" : {
"parameters" : {
"additionalProperties" : 0
},
"permissions" : {
"user" : "all"
},
"returns" : {
"type" : "array",
"items" : {
"type" : "object",
"properties" : {}
},
"links" : [
{
"rel" : "child",
"href" : "{name}"
}
]
},
"name" : "index",
"method" : "GET",
"description" : "Cluster index."
}
}
}
];
Ext.onReady(function() { ... }
In this case, the end can be found by matching a semicolon at the end of a line:
if (preg_match('/^var pveapi = (.*?);$/ms', $js, $matches)) {
$data = json_decode($matches[1]);
print_r($data);
}
Per default the RegEx engine operates greedily on individual lines, so you'd have to tell it to do the opposite – the RegEx you seem to be looking for would be
#\spveapi\s*=\s*(.*?);\s*$#s
What it does is:
#
Start the expression
\s
Make sure the variable name is preceded by whitespace, so it's not part of a different variable name
pveapi
Find the variable
\s*=\s*
Make sure there's an equal sign with optional whitespace around it
(.*?);\s*$
Get as few characters as possible before finding a semicolon – i.e. all characters until the first semicolon that is follow only by optional whitespace and a line ending
#ms
End the expression and tell it to let . match line endings too and match $ to the ending of each line

Regular Expression: pull part from string. with JS

Hey all im not every good with regexp i was hoping someone could help.
ok so this is the sting "KEY FOUND! [ 57:09:91:40:32:11:00:77:16:80:34:40:91 ]"
And i need to pull "57:09:91:40:32:11:00:77:16:80:34:40:91", now this key can be meany length not just as written here and with or with out the ":"
now the second sting i would like to test and extract is: "[00:00:09] Tested 853 keys (got 179387 IVs)", i would like to pull "00:00:09" and "853" and "179387".
this would be the raw string http://regexr.com?31pcu or http://pastebin.com/eRbnwqn7
this is what im doing now.
var pass = new RegExp('KEY FOUND\!')
var tested = new RegExp('Tested')
var fail = new RegExp('\Failed. Next try with ([0-9]+) IVs')
var data="Look at the link i added"
if (tested.test(data)) {
self.emit('update', mac, {
'keys' : data.split('Tested ')[1].split(' keys ')[0],
'ivs' : data.split('got ')[1].split(' IVs')[0]
});
} else if (pass.test(data)) {
var key = data.split('KEY FOUND! [')[1].split(' ]')[0].split(':').join('');
} else if (fail.test(data)) {
console.log(data);
}
thanks all
Edit:
I have added more the the question to help with the answer
If it is always surrounded by [] then it is simple:
\[([\s\S]*)\]
This will match any characters enclosed by [].
See it in action here.

Categories

Resources