Replace string globally using veriable - javascript

I'm trying to replace string globally using the variable, but getting an unexpected replacement while replacing it. I've searched the same issue but didn't get any solutions so I'm posting it here. Maybe you guys will lead me where I'm doing a mistake.
Here is the case:
I have an HTML mail body and a list of links that I've extracted from the mail body and stored it as an array.
I'm trying to iterate the links array and try to find the match from the mail body.
And when I'm using the replace() method to replace the link by adding some prefix.
Looks pretty straight forward, right?
Here is the issue I'm getting while replacing the links.
There are some repeated links I've. While trying to replace them with the prefix, it is getting replace 2 times.
for e.x.
prefix = 'http://this.prefix?redirect_uri='
link = 'http://google.com'
// Expected Output
http://this.prefix?redirect_uri=http://google.com
// Getting Output
http://this.prefix?redirect_uri=http://this.prefix?redirect_uri=http://google.com
You can see the prefix is getting repeated.
I'm sharing my actual code, So, it will be more helpful to you guys to understand what I mean to say.
let mailBody = `
<div dir="auto">
aabc.pagerduty.com
[FIRING:1] TooManyContainerRestarts (http 10.0.95.123:8080 kube-state-metrics newton newton/prometheus-operator-prometheus prometheus-operator-kube-state-metrics infra critical) </p>
View Incident
<p>URGENCY </p>
</div>
`;
const links = [
'https://aabc.pagerduty.com/incidents',
'https://aabc.pagerduty.com/incidents/P9X3024'
]
const processTrackingLinks = (linkArray, mailBody) => {
const prefix = 'https://test.io?redirect_uri=';
// const mapping = [];
for (let i=0; i < linkArray.length; i++){
const replacer = new RegExp(linkArray[i], 'g')
mailBody = mailBody.replace(replacer, prefix + linkArray[i]);
}
return mailBody;
};
mailBody = processTrackingLinks(links, mailBody);
console.log(mailBody);
If you have any idea why it is happening,
Am I doing something wrong or it is an issue
just let me know.
Any resolution will be appreciated. :)

How about this approach. You don't need the links array anymore.
const process = mailBody => {
return mailBody.replace(/href="/g, `href="http://test.io?redirect_uri=`)
}

The problem lies in the links array you are using. Double replacement is due to the fact that "https://abc.pagerduty.com/incidents" is a substring of "https://abc.pagerduty.com/incidents/".
Use the following array instead:
let links = [
'https://abc.pagerduty.com/incidentsgoogle',
'https://abc.pagerduty.com/incidents/',
'https://abc.facebook.com'
];
As seen already, this approach would fail for strings with substring present in the links array.
To avoid such issues, change the process function to:
const process = (links, mailBody) => {
let prefix = 'http://test.io?redirect_uri='
return mailBody.replace(/( href=["'])/g, "$1" + prefix);
};

Related

How do I parse a .csv file with quotes and commas within the quotes Node.js

I have a solution that parses a csv, however it does not take into account data that has a comma within the quoted field. (example "not, accounted","normal")
let filePath = Path.resolve(__dirname, `./MyData.csv`);
let data = fs.readFileSync(filePath, 'utf-8');
data = data.replace(/"/g, '');
data = data.split(/\r?\n/);
for (let i in data) {
data[i] = data[i].split(",");
}
data.forEach(async customerEmailToAdd => {
if (customerEmailToAdd[0] != 'id') {
const sql = `
UPDATE customers
SET contactEmail = '${customerEmailToAdd[4]}',
contactName = '${customerEmailToAdd[3]}'
WHERE Id = '${customerEmailToAdd[0]}';
`;;
await queryInterface.sequelize.query(sql);
};
});
You issue is that you are trying to use split and replace to parse a .csv and this 2 functions are not a really good idea for this (for a lot of specific cases, like a wild comma in a value). You should consider reading the file character by character using a state machine to know what you are reading. Because you can also find something like this: "not, \"accounted\""
But, if you want to keep with your current method, you can replace the comma that are between two quotes by a temporary placeholder. Something like ###COMMA###, just make sure that this placeholder will never appear in a real case.
You can use the following code for this : data = data.replace(/"(.*?)"/g, (str) => str.replaceAll(',', '###COMMA###'));
Then you use split and replace to parse the csv file, and you replace the placeholder by real commas : data = data.replaceAll('###COMA###', ',');

Searching a string

OK Ive been able to get the following to partially work
var Global_Wound_array =[{"WoundNumber":1,"BodySide":"Front","BodyPart":"Nose"},{"WoundNumber":2,"BodySide":"Left","BodyPart":"Head"},{"WoundNumber":3,"BodySide":"Back","BodyPart":"Ear"}]
var Global_Wound_Counter = 1
I can get the page to loop through and display the individual wounds but I need a way to say at a particular page one of the values eg on WoundNumber 2 BodyPart has changed and updated the string without affecting the rest of it.
page9200.setEventHandler("pageFinishing", function () {
//getSelectedButtonLabel this is ok - specific on the system
let Q1 = Q3_WoundNumber.getValue();
let Q2 = Q1_BodySide.getSelectedButtonLabel();
let Q3 = Q2_BodyPart.getSelectedButtonLabel();
for (var i = 0; i < Global_Wound_array.length; i++) {
if (i+1 == Q1){
//create new temp variable array
var Temp_Wound_obj2 = {"WoundNumber": Q1,"BodySide": Q2,"BodyPart":Q3}
Global_Wound_array.push(Temp_Wound_obj2)
}
}
});
As well as being able to reach the end of the string to present a blank set of values to have the option to add a new wound.
Every time I think Ive got something that looks like it would work I go around in circles, when I try to update the system at the end I get and error that the - invaid parameters for RPC call: variable is bad
It seems you are pasting JSON onto JSON, with no separator. This creates a messy and non-standard data structure. If you wrote your JSON with a newline at the end, you would end up with a JSONL file, which is very simple to process.
const jsonl = `
[{"WCount":1,"Side":"Centre","Part":"Ocipit","Type":"Other","SurroundingSkin":"Dermatitis","Height":"","Width":"","Depth":""}]
[{"WCount":2,"Side":"Front","Part":"Neck","Type":"Diabetic foot wound","SurroundingSkin":"Healthy/intact","Height":"3","Width":"4","Depth":"5"}]
`;
const jsonItems = jsonl.trim().split("\n");
const lastJsonItem = jsonItems[jsonItems.length - 1];
const lastItem = JSON.parse(lastJsonItem);
const lastWCount = lastItem[0].WCount;
console.log(lastWCount);
If you already have a file without newlines... it would be best to insert them, and correct your data to JSONL. This is simple in your case just by replacing ][ with ]\n[ (and making sure the file ends with a newline too, so the next write would not be messed up), since you have no nesting and (hopefully) no ][ in your text, but in general it is not easy - I don't know of a JSON parser that will return unconsumed text, so it would probably involve writing a JSON parser. Much easier to write data correctly in the first place.

Removing unnecessary string after grabbing a website link.- Discord.JS

This is my first time posting on StackOverflow so I apologize for any mistakes I made.
I want to remove unnecessary words after yoinking a link from a different channel.
Code so far:
message.content = message.content.toLowerCase();
let checker = 'roblox.com/games/59'
if(message.content.search(checker) >= 8){
let embed = new discord.RichEmbed()
.setTitle("**Possible condo found!**")
.setColor(randomColor)
.setDescription("Grabbed: "+ message.content +"")
client.channels.get("809420315230339112").send({ embed: embed })
}
This is the output after grabbing a link.
Grabbed: https://www.roblox.com/games/5924680090/chromosome-ss-Place this my game it cool
I want to remove the following string so it only leaves the link present.
this my game it cool
Ideas?
You could probably use regex for this and check if there is a string that looks like a URL. The regex (((https?:\/\/)|(www\.))[^\s]+) checks if a string contains http, https, www and using the .match() method you can grab all these matched strings into an array.
Try the snippet below:
const content = "Oh, https://roblox.com/games/5924680090/chromosome-ss-Place this my game it cool. Another cool link: https://stackoverflow.com :)"
const urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/gi
const urls = content.match(urlRegex)
const robloxLink = urls && urls[0]
console.log({ urls, robloxLink })
You could also move it to its own function and use it like this:
function findLinks(string) {
const urlRegex = /(((https?:\/\/)|(www\.))[^\s]+)/gi
return content.match(urlRegex)
}
const content = "Oh, https://roblox.com/games/5924680090/chromosome-ss-Place this my game it cool. Another cool link: https://stackoverflow.com :)"
console.log(findLinks(content))
Or, you can use an npm package like get-urls.
This example separates the string at each space and creates an array from it. Then .slice() removes all but the first element.
const grabbedLink = " https://www.roblox.com/games/5924680090/chromosome-ss-Place this my game it cool"
const onlyLink = grabbedLink.trim().split(' ').slice(0, 1);
console.log(onlyLink);
References:
.split()
.slice()
.trim()

Modify regex pattern to capture nested tags into an array of objects

I'm trying to create a regex pattern to match "faux" html tags for a small application i am building.
I have created the regex to capture found matches within {tag}brackets{/tag} and output them into an array of objects like so:
{
{key : value},
{key : value}
}
Code with the current pattern:
let str = "{p}This is a paragraph{/p} {img}(path/to/image) {ul}{li}This is a list item{/li}{li}Another list item{/li}{/ul}";
let regex = /\{(\w+)}(?:\()?([^\{\)]+)(?:\{\/1})?/g;
let match;
let matches = [];
while (match = regex.exec(str)) {
matches.push({ [match[1]]: match[2]})
}
console.log(matches)
Link to JSbin
I have realized I need the pattern to capture nested groups as well, and put these into an array – so the result for the above string would be:
[
{p : "This is a paragraph"},
{img : "path/to/image"},
{ul : ["This is a list item", "Another List item"]}
]
The idea here is to match each tag in order, so that the indexes of the array match the order they are found (i.e. first paragraph in the string above is array[0] and so forth).
If anyone has a bit of input on how I could structure the pattern that would be greatly appreciated.
I will not have more than 1 level deep nesting, if that makes any difference.
I am flexible to use a different markup for the ul if this would help, however I cannot use square brackets [text] due to conflicts with another function that generates the text I am trying to extract in this step.
Edit: An idea that hit me is to have a third capturing group to capture and push to the list-array, but I am unsure whether or not this would work in reality? I have not gotten it to work so far
JavaScript has no support for recursion within regular expressions, which would otherwise be a potential solution.
I would however go for a different solution:
You could rely on DOMParser -- available in browsers, or if you are on Node, there is similar functionality available in several modules.
To use it, you need to have an XML formatted string, so unless you want to use <p> style of tags, you'd first have to convert your string to that, making sure that content with < would need to get < instead.
Also the {img} tag would need to get a closing tag instead of the parentheses. So a replacement is necessary for that particular case.
Once that is out of the way, it is quite straightforward to get a DOM from that XML, which might already be good enough for you to work with, but it can be simplified to your desired structure with a simple recursive function:
const str = "{p}This is a paragraph{/p} {img}(path/to/image) {ul}{li}This is a list item{/li}{li}Another list item{/li}{/ul}";
const xml = str.replace(/\{img\}\((.*?)\)/g, "{img}$1{/img}")
.replace(/</g, "<")
.replace(/\{/g, "<").replace(/\}/g, ">");
const parser = new DOMParser();
const dom = parser.parseFromString("<root>" + xml + "</root>", "application/xml").firstChild;
const parse = dom => dom.nodeType === 3 ? dom.nodeValue.trim() : {
[dom.nodeName]: dom.children.length
? Array.from(dom.childNodes, parse).filter(Boolean)
: dom.firstChild.nodeValue
};
const result = parse(dom).root;
console.log(result);
The output is almost what you intended, except that that li elements are also represented as { li: "...." } objects.

Javascript: working with query string

I'm trying to write a Javascript function to get the query string of the browser and allow a new key/value to be passed to the function. If the key exists, I need to replace the value. Since I've spent the last 3.5 hours on this, I haven't yet gotten around to the replacing part.
So far, I'm using the answer here: How to get the query string by javascript? to get the query string. However, it doesn't appear to work... The URL I was testing with was: http://www.site.com/poo?drwho=tombaker&companion=k9
var assoc = {};
var decode = function (s) { return decodeURIComponent(s.replace(/\+/g, " ")); };
var queryString = location.search.substring(1);
var keyValues = queryString.split('&');
for(var i in keyValues) {
var key = keyValues[i].split('=');
assoc[decode(key[0])] = decode(key[1]);
}
if(assoc["dr"] === undefined ) {
// not found. todo: replace
}
I'd really appricate any help! Is there any simpler way of doing this using JQuery?
Copy and pasted your code here: http://jsfiddle.net/6KcWh/5/, and added a call to JSON.stringify() to examine the contents of assoc. It turns out assoc is not undefined. But, of course assoc.dr is undefined, because there is no querystring argument of dr. There is a querystring argument of drwho. It looks like you were looking for the wrong querystring argument.
You appear to be misusing for...in.
Try converting your for loop to a standard for (i = 0 ; i < keyValues.length; i++) and check out some other answers about what for...in is used for in JavaScript.

Categories

Resources