JS/JQUERY: How to match and replace occurances inside specified strings? - javascript

I swear i tried figuring this out myself all day, but my regex-foo is just not that good.
I'm trying to create a small parser function to convert strings with urls to html coded and tags
I know how complex a regex can be trying to figure out which urls to covert to what from a big string, so what I did is simply prefix the string to covert with a flag to tell the parser how to format it, and post fix it with the ";" char to tell the parser where that particular URL ends. This way the parser has lesser guest work to do resulting in easier to regex-match and faster for execution. I really dont need a generalize match and replace all.
So my formatting is as follows, where "X" is the url string:
For URLs it will be url=X;
For IMAGES it will be img=X;
so anything in between my prefix and post fix must be converted accordingly..
So for example, for images in my document, the string could be:
click this image img=http://example.com/image1.jpg;
and i need that converted to
click this image <a href="http://example.com/image1.jpg" target="_blank">
<img class="img img-responsive" src="http://example.com/image1.jpg"/></a>
I am able to do this easily in PHP buy preg_match() function
preg_match('/\img=(.+?)\;/i', $item_des, $matches)
here's the code block:
I decided to push this routine to the browser instead of the backend (PHP) so i need similar or better JS solution.
Hoping anyone can help here, thanks!

try code below:
var str = "click this image img=http://example.com/image1.jpg;image2 img=http://example.com/image2.jpg;"
var phrases = str.split(';');
var totalRes = '';
phrases.forEach(function(str){
totalRes += processPhrase(str);
});
console.log(totalRes);
function processPhrase(str) {
var img = str.split('img=')
var res = '';
if (img.length > 1) { //img=X
var url = img[1].replace(';', '');
res = img[0] + "<a href='" + url + "' target='_blank'><img src='" + url + "'/></a>";
} else {
var url = str.split('url=');
//Do for url=X here
}
console.info(res);
return res;
}

You can use this regexp /(img|url)=(.+?);/g:
(img|url) : the type, should be grouped so we will know what to do with the value
= : literal "="
(.+?) : a number of characters (use the non-greedy ? so it will match as fewer as possible)
; : literal ";"
Read more about non-greedy regexps here.
Example:
var str = "click this image img=http://i.imgur.com/3wY30O4.jpg?a=123&b=456; and check this URL url=http://google.com/;. Bye!";
// executer is an object that has functions that apply the changes for each type (you can modify the functions for your need)
var executer = {
"url": function(e) {
return '<a target="_blank" href="' + e + '">' + e + '</a>';
},
"img": function(e) {
return '<a target="_blank" href="' + e + '"><img src="' + e + '"/></a>';
}
}
var res = str.replace(/(img|url)=(.+?);/g, function(m, type, value) {
return executer[type](value); // executer[type] will be either executer.url or executer.img, then we pass the value to that function and return its returned value
});
console.log(res);

Related

replace a pattern with URL

The idea is taken from here
I have the following code:
myApp.filter('parseUrlFilter', function () {
var urlPattern = /^E\d{5}-\d{2}$/;
return function (text, target) {
return text.replace(urlPattern, '<a target="' + target + '" href="http://somepage.com?number=$&">$&</a>') + " | ";
};
});
I'm still trying to understand how this code exactly works but it does not convert the text to URL.
Like E12345-01 does not become somepage.com?number=E12345-01
I think I'm missing something about how the regex works here. Any help will be appreciated.
Edit: added plnkr with somewhat working answer of machinehead115
Without seeing you HTML code I assume that you are actually binding / using the filter there, like so:
<div ng-bind-html="'E12345-01' | parseUrlFilter:'_blank'"></div>
In order to have the filter actually output the link text as code you need to include $sce as a dependency of filter and return the link using $sce.trustAsHtml(link):
angular.module('app', [])
.filter('parseUrlFilter', function($sce) {
var urlPattern = /^E\d{5}-\d{2}$/;
return function(text, target) {
return $sce.trustAsHtml(text.replace(urlPattern, '<a target="' + target + '" href="http://somepage.com?number=$&">$&</a>') + ' | ');
};
});
Here is an example plnk of the code working.
I'm not sure I understand your question, nor your context. My assumption is that you need to extract the number from an incomingString and use that number to generate a new link string. Given those requirements, the below would get you going...
//this var represents the string that would hold the identifier you're interested in
var originString = "blah blah blah E12345-01 more blah blah blah";
function DoIt(incomingString)
{
//create a regex pattern
var urlPattern = new RegExp(/E\d{5}-\d{2}/);
//get the match
var theMatch = urlPattern.exec(incomingString);
//add the match to your new url
var returnString = "www.whateversite.com/number=" + theMatch;
//from here you can do whatever you want with that string
//for now, I'll just return it as is...
return returnString;
}
console.log(DoIt(originString));
here is the working regex for you
([E]\d{5}-\d{2})
check here https://regex101.com/r/O6YFlj/1
The problem is not in your URL matching and replacement code. I extracted the following from your code and used it. Worked perfect:
<script>
var urlPattern = /^E\d{5}-\d{2}$/;
var text = "E12345-01";
document.write(text.replace(urlPattern, '$&') + " | ");
</script>
The issue must be with the value of text. use console.log(text) to see whether you're getting the right value in your variable or not.

Update uri hash javascript

I find it hard to believe this hasn't been asked but I can find no references anywhere. I need to add a URI hash fragment and update the value if it already is in the hash. I can currently get it to add the hash but my regex doesn't appear to catch if it exists so it adds another instead of updating.
setQueryString : function() {
var value = currentPage;
var uri = window.location.hash;
var key = "page";
var re = new RegExp("([#&])" + key + "=.*#(&|$)", "i");
var separator = uri.indexOf('#') !== -1 ? "&" : "#";
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
}
else {
return uri + separator + key + "=" + value;
}
},
Also if this can be made any cleaner while preserving other url values/hashes that would be great.
example input as requested
Starting uri value:
www.example.com#page=1 (or no #page at all)
then on click of "next page" setQueryString gets called so the values would equal:
var value = 2;
var uri = '#page1'
var key = 'page'
So the hopeful output would be '#page2'.
As to your regex question, testing if the pattern #page=(number) or &page=(number) is present combined with capturing the number, can be done with the regex /[#&]page\=(\d*)/ and the .match(regex) method. Note that = needs escaping in regexes.
If the pattern exists in the string, result will contain an array with the integer (as a string) at result[1]. If the pattern does not exist, result will be null.
//match #page=(integer) or &page=(integer)
var test = "#foo=bar&page=1";
var regex = /[#&]page\=(\d*)/;
var result = test.match(regex);
console.log(result);
If you want to dynamically set the key= to something other than "page", you could build the regex dynamically, like the following (note that backslashes needs escaping in strings, making the code a bit more convoluted):
//dynamically created regex
var test = "#foo=bar&page=1";
var key = "page"
var regex = new RegExp("[#&]" + key + "\\=(\\d*)");
var result = test.match(regex);
console.log(result);

Regex mapping in Firefox context menu contentScript

I am developing context menu add-on for Firefox. I am trying to get the selectedText and validate if it is a number. If it is a number i am using that number value to process further.
But, i got stuck at a point where i am trying to replace [(,)] using regex in javascript replace method.
Following is the code which fails to map any number starting/ending with ( or ):
var menuItemLRG = contextMenu.Item({
label: "LRG",
data: "http://myurl/&val=:",
contentScript: 'self.on("click", function (node, data) {' +
' var selectedText = window.getSelection().toString();' +
' var formattedText1 = selectedText.trim();' +
' var formattedText2 = formattedText1.replace(/^[,\[\]()]*/g,"");' +
' var formattedText3 = formattedText2.replace(/[,\[\]()]*$/g,"");' +
' console.log(formattedText3); '+
' var regExp = new RegExp(/^[0-9]+$/);' +
' if (regExp.test(formattedText3) == true) {' +
' console.log("URL to follow :"+data+formattedText3);' +
' window.open(data+formattedText3);' +
' } '+
'});'
});
Above code fails to replace ( or ) in sample inputs: (5663812, 11620033).
But, a vanilla test like the following succeeds:
<script>
var str = "(2342423,])";
var tmpVal1 = str.replace(/^[,\[\]()]*/g,"");
var tmpVal2 = tmpVal1.replace(/[,\[\]()]*$/g,"");
var regExp = new RegExp(/^[0-9]+$/);
if (regExp.test(tmpVal2) == true) {
alert(tmpVal2);
}
</script>
After many trial and error found the issue. When we try to escape a character inside a single quotes we need to add one more escape for the escape character to get recognized, otherwise the single escape \] will be considered as ] which leads to abrupt ending of of the regex pattern.
In this case:
' var formattedText2 = formattedText1.replace(/^[,\[\]()]*/g,"");'
is decoded as :
var formattedText2 = formattedText1.replace(/^[,[]()]*/g,"");
instead of as:
var formattedText2 = formattedText1.replace(/^[,\[\]()]*/g,"");
So, by adding one more escape character for an escape character resolved the pattern correctly:
' var formattedText2 = formattedText1.replace(/^[,\\[\\]()]*/g,"");'
Sorry for wasting your time in analyzing the cause, if any.

Javascript replace multiple images calls with regex

I need to write a script that reads an HTML file in which there are multiple images declared. The thing is the call to the image is simple and I need to add several instructions. From this code :
<img src="myImage1.jpg" class="image_document">
<img src="myImage2.jpg" class="image_document">
I have to get this :
<a onclick="bloquedefilementchapitres();" href="articles/myImage1.jpg" class="fancybox" rel="images"><img src="articles/myImage1.jpg" class="image_document"></a>
<a onclick="bloquedefilementchapitres();" href="articles/myImage2.jpg" class="fancybox" rel="images"><img src="articles/myImage2.jpg" class="image_document"></a>
So, I tried to use regex to perform this thinking that every image could be detected by regex. Then, every filename could be stored in an array so that I would be able to use the filename to write the link.
Here is what I did :
var recherche_images,
urls = [],
str = theHTMLcode,
rex = /<img[^>]+src="?([^"\s]+)"/g;
while (recherche_images = rex.exec(str)) {
urls.push(recherche_images[1]);
}
for (var v = 0; v < urls.length; v++) {
str = str.replace(/<img src=\"/, '<a onclick=\"bloquedefilementchapitres();\" href=\"articles/' + urls[v] + '\" class=\"fancybox\" rel=\"images-' + idunite + '\"><img src=\"articles/');
}
str = str.replace(/image_document\">/g, 'image_document\"></a>');
If the HTML document only contains one image, it works. If two images are declared, the program loops on the first image and ignores the second image.
Is there any way to tell to the replace function to start at a certain point in the string? Is there any better way to perform this?
There are better ways to achieve this as noted in the comments to your question.
Regarding your code:
There is an issue with the for loop in your code - v++ is executed twice - one in the for loop increment condition and once in the body.
Another issue is the way the .replace() method has been used. Without the \g flag in the regex, the replace() method will just find and replace the first occurrence. Check documentation and this SO question for more details.
Check the code below which uses the /g operator in the regex to find all img matches in the string and each match is passed to a function which returns the replacement string.
What you need is something like this:
var recherche_images,
urls = [],
str = '<img src="myImage1.jpg" class="image_document"><img src="myImage2.jpg" class="image_document">',
rex = /<img[^>]+src="?([^"\s]+)"/g;
while (recherche_images = rex.exec(str)) {
urls.push(recherche_images[1]);
console.log(recherche_images[1]);
}
var idunite = 'test"';
var v = -1;
str = str.replace(/<img src=\"/g, function(mtch) {
v++;
return '<a onclick=\"bloquedefilementchapitres();\" href=\"articles/' + urls[v] + '\" class=\"fancybox\" rel=\"images-' + idunite + '\"><img src=\"articles/';
});
str = str.replace(/image_document\">/g, 'image_document\"></a>');
console.log(str);
JSFiddle.
Pure JS solution:
var x = document.getElementsByClassName('image_document');
for (var i = 0; i < x.length; i++) {
var obj = x[i];
var n = document.createElement('a');
n.href = "articles/" + obj.attributes.src.value;
obj.src = "articles/" + obj.attributes.src.value;
n.className = "fancybox";
n.rel = "images";
n.innerHTML = obj.outerHTML;
n.addEventListener('click', bloquedefilementchapitres);
console.log(n);
obj.parentNode.replaceChild(n, obj);
}
<img src="myImage1.jpg" class="image_document">
<img src="myImage2.jpg" class="image_document">
It seems like you can do this with a single global replace:
For example if your HTML string is in a variable called s then it would be:
s.replace(/<img src="([^\"]+)" class="image_document">/g,
"<a onclick=\"bloquedefilementchapitres();\" href=\"articles/$1\" class=\"fancybox\" rel=\"images\"><img src=\"articles/$1\" class=\"image_document\"></a>");
That seems to work for me ok in the console for a string with one or many img tags. Apologies if I'm missing additional complexity/requirements.

Regex to match markdown image pattern with the given filename

I want to replace a markdown image pattern with the given filename in the textarea with an empty string.
So the pattern is ![alt](http://somehost/uploads/filename.jpg)
This is the code I have now:
var content = target.val();
var fileName = someDynamicValue;
var regex = new RegExp(RegExp.escape('![') + '.*' + RegExp.escape(']') + RegExp.escape('(') + '.*' + RegExp.escape(fileName) + RegExp.escape(')'), 'i');
var found = regex.exec(content);
var newContent = content.replace(regex, "");
target.val(newContent);
RegExp.escape= function(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
};
For example var fileName = filename.jpg. Then I need to match ![alt](http://somehost/uploads/filename.jpg) and replace it with an empty string.
Everything works great if the content includes one image. But if there are more then one, for example:
Some text ![alt](http://somehost/uploads/filename.jpg) some text ![alt2](http://somehost/uploads/filename2.jpg) more text.
then var found includes ![alt](http://somehost/uploads/filename.jpg)![alt2](http://somehost/uploads/filename2.jpg), but I need to match only ![alt](http://somehost/uploads/filename.jpg).
What regex I need in this case?
Use non-greedy quantifiers will do:
!\[(.*?)\]\((.*?)\)
You can check it out online: https://regex101.com/r/kfi8qI
Not sure how you are trying to put the strings together but
'.*' is greedily matching up to the last filename.
So, it should probably be '.*?'.
However, if the filenames are different then it shouldn't have matched.
Another thing is you should in general stop it from running past the next [alt] with
something like '[^\[\]]*'
Edit:
RegExp.escape('![') + '.*' + RegExp.escape(']') + RegExp.escape('(') + '.*' + RegExp.escape(fileName) + RegExp.escape(')'), 'i');
is the culprit.
Try
RegExp.escape('![') + '[^\]]*' + RegExp.escape(']') + RegExp.escape('(') + '[^\[\]]*?' + RegExp.escape(fileName) + RegExp.escape(')'), 'i');

Categories