How to get the start and last index of a string match - javascript

I am trying to get the last and first index of a string match. For example:
var text = 'I am a string and this is an image <img src="image.jpeg">';
What I would like to do is get the first index and last index of the match. example I have attempted:
<script>
function getLightBox(text) {
var result = str.match(/<img src="(.*?)>/g).map(function(val){
var res = val.replace(/<\/?img src =">/g,'').replace(/?>/g,'');
var tag1 = text.firstIndexOf((/<img src="(.*?)>/g));
var tag2 = text.lastIndexOf((/<img src="(.*?)>/g));
var anchor1 = '<a href="images/' + res +'" data-lightbox="Christmas">';
var anchor2 = '</a>'
var newString = text.substring(0,tag1) + anchor1 + '<img src="' + res + '">' + anchor2 + text.substring(tag2,text.length);
return newString;
});
</script>
wanted output
I am a string and this is an image <img=src"image.jpeg">
I'm unsure if this is the correct way, it doesnt seem to work for me.
Thanks.

You are almost there, I've made some changes:
The regex pattern needs to have .*? to match lazily up to the next src attribute or the > closing tag.
The method used is String.replace, because it allows to have the full matched image img, and also to have the src matched group () in the second argument.
Using string interpolation `` (backticks) eases the concatenion of the resulting string.
Look the final function:
function getLightBox(text = '') {
return text.replace(/<img.*?src="([^"]+)".*?>/g, (img, src) => {
return `${img}`;
});
}
const element = document.getElementById('myElement');
element.innerHTML = getLightBox(element.innerHTML);
img {
padding: 0 10px;
background-color: yellow;
}
a {
padding: 0 20px;
background-color: red;
}
<div id="myElement">
I am a string and this is an image:
<img id="foo" src="image.jpeg" alt="bar">
</div>
You can play with the regex pattern here:
https://regex101.com/r/79HHrn/1

Related

HTML and Javascript: Remove a complete tag with dynamic content inside from string

I have a string that conains HTML. In this HTML I have a textbox with text inside:
<div class="aLotOfHTMLStuff"></div>
<textbox>This textbox must be terminated! Forever!</textbox>
<div class="andEvenMoreHTMLStuff"></div>
Now I want to remove the textbox from that string, including the text inside. The desired result:
<div class="aLotOfHTMLStuff"></div>
<div class="andEvenMoreHTMLStuff"></div>
How can I achieve it? The two main problems: It is a string and not part of the DOM and the content inside the textbox is dynamic.
Here is an example that will look for the opening and closing tags in the string and replace anything in between.
const template = document.querySelector('#html')
const str = template.innerHTML
function removeTagFromString(name, str) {
const reg = new RegExp('<' + name + '.*>.*<\/'+ name +'.*>\\n*', 'gm')
return str.replace(reg, '')
}
console.log('before', str)
console.log('after', removeTagFromString('textbox', str))
<template id="html">
<div class="aLotOfHTMLStuff"></div>
<textbox>This textbox must be terminated! Forever!</textbox>
<div class="andEvenMoreHTMLStuff"></div>
</template>
If it is text string not HTML, you can convert it to DOM:
var str = '<div class="aLotOfHTMLStuff"></div><textbox>This textbox must be terminated! Forever!</textbox><div class="andEvenMoreHTMLStuff"></div>';
var $dom = $('<div>' + str + '</div>');
Then remove element from DOM:
$dom.find('textbox').remove();
If you need, can get string back:
console.log($dom.html());
Try this:
var string = '<div class="aLotOfHTMLStuff"></div><textbox>This textbox must be terminated! Forever!</textbox><div class="andEvenMoreHTMLStuff"></div>';
if ( string.includes("<textbox>") ) {
var start = string.indexOf("<textbox>");
var stop = string.indexOf("</textbox>");
string = string.replace(string.slice(start, stop+10), "");
}
console.log(string);
You can use parseHTML to convert string to html,
like..
var str = '<div class="aLotOfHTMLStuff"></div><textbox>This textbox must be terminated! Forever!</textbox><div class="andEvenMoreHTMLStuff"></div>';
var a = $.parseHTML(str);
var newstr = "";
a.forEach(function(obj) {
if ($(obj).prop('tagName').toLowerCase() != "textbox") {
newstr += $(obj).prop("outerHTML")
}
});
It's very simple and you can remove any tag in future by just replacing "textbox"
It is a string and not part of the DOM and the content inside the
textbox is dynamic.
So that html is in a js variable of type string? like this?:
var string = '<div class="aLotOfHTMLStuff"></div><textbox>This textbox must be terminated! Forever!</textbox><div class="andEvenMoreHTMLStuff"></div>';
So in that case you could use .replace(); like this:
string = string.replace('<textbox>This textbox must be terminated! Forever!</textbox>', '');

Regex, doesnt stop matching

I'm working on a bbcode example, but i cannot seem to get it to work.
the regex matches all the [img] tags and make it all look wierd. I'm trying to have the option to click on the image and get it full size and when I do, everything becomes a link (when i have more than once img-tag).
Here's my text:
[img size="small" clickable="no"]img1.jpg[/img]
[img size="large" clickable="yes"]img2.jpg[/img]
Here's my source code:
var bbArray = [/\n/g,
/\[img size="(.*?)" clickable="yes"\](.*?)\[\/img\]/g,
/\[img size="(.*?)" clickable="no"\](.*?)\[\/img\]/g];
var bbReplace = ['<br>',
'<img src="'+path+'img/$1_$2?'+ new Date().getTime() +'" alt="$2">',
'<img src="'+path+'img/$1_$2?'+ new Date().getTime() +'" alt="$2">'];
The operation:
for (var i = 0; i < content_text_bb.length; i++) {
content_text_bb = content_text_bb.replace(bbArray[i], bbReplace[i]);
}
the result:
<img src="localhost/img/small" clickable="no" ]img1.jpg[="" img]
[img size="large_img2.jpg?1423317485160" alt="img2.jpg">;
I'm not that familiar with regex and I really need someone to look at it, I'm lost.
Something that may be of interest to you, Extendible BBCode Parser. An example of use.
var bbcArr = [
'[img size="small" clickable="no"]img1.jpg[/img]',
'[img size="large" clickable="yes"]img2.jpg[/img]'
];
XBBCODE.addTags({
"img": {
openTag: function(params, content) {
params = (params.match(/(\S+?=".*?")/g) || [])
.reduce(function(opts, item) {
var pair = item.match(/(\S+?)="(.*?)"/);
opts[pair[1]] = pair[2];
return opts;
}, {});
var html = '<img src="http://localhost/img/';
if (params.clickable === 'yes') {
html = '<a href="http://localhost/img/' + content +
'" alt="' + content + '">' + html;
}
if (params.size === 'small' || params.size === 'large') {
html += params.size + '/';
}
html += content + '" />';
if (params.clickable === 'yes') {
html += '</a>';
}
return html;
},
closeTag: function(params, content) {
return '';
},
displayContent: false
}
});
bbcArr.forEach(function(item) {
var result = XBBCODE.process({
text: item,
removeMisalignedTags: false,
addInLineBreaks: false
});
this.appendChild(document.createTextNode(result.html + '\n'));
}, document.getElementById('out'));
<script src="https://rawgithub.com/patorjk/Extendible-BBCode-Parser/master/xbbcode.js"></script>
<pre id="out"></pre>
First thing first, your loop should be:
for (var i = 0; i < bbArray.length; i++) {
(not content_text_bb.length)
Secondly, the issue you have is with this size="(.*?). This says: match any content non-greedily till I find the first "thing-that-follow" (in this case the thing-that-follows is the first occurrence of " clickable="yes"
If you look at your input text, the search for [img size="{ANYTHING}" clickable="yes"] means that {ANYTHING} is: small" clickable="no"]img1.jpg[/img][img size="large and you can see how that returns your results, and breaks everything.
So, it should firstly be noted that regexps are not the best tool for language processing (plenty of posts on SO and the internet at large on the topic). In this particular case, you can fix your problem by being very specific about what you want matched.
Do NOT match "anything". If you want to match a size attribute, look for digits only. If you want to match any property value, look for "{ANYTHING_NOT_DOUBLE_QUOTES}". So, with that said, if you change bbArray to the code below, it should work in the particular example you have given us:
var bbArray = [/\n/g,
/\[img size="([^"]*)" clickable="yes"\](.*?)\[\/img\]/g,
/\[img size="([^"]*)" clickable="no"\](.*?)\[\/img\]/g];
Just to be clear: while this should work on your current input, it is by no mean robust bbcode processing. It will only match [img] bbcode tags that have exactly one size attribute and one clickable attribute, in that order!! Most free-to-type bbcode out-there will have much broader variations, and this code obviously won't work on them.

li append function not work

I'm using blogger as my blogging platform. In my blog homepage, I create a function to grab all images from single post for each post (there are 5 posts in my homepage), then append all images from single post to single slider, for each post.
This is my function script (I place it after <body> tag):
<script type='text/javascript'>
//<![CDATA[
function stripTags(s, n) {
return s.replace(/<.*?>/ig, "")
.split(/\s+/)
.slice(0, n - 1)
.join(" ")
}
function rm(a) {
var p = document.getElementById(a);
img = p.getElementsByTagName("img").each( function(){
$(".flexslider .slides").append($("<li>").append(this));
});
p.innerHTML = '<div class="entry-container"><div class="entry-content"><div class="entry-image"><div class='flexslider'><ul class='slides'></ul></div></div><div class="entry-header"><h1>' + x + '</h1></div><p>' + stripTags(p.innerHTML, SNIPPET_COUNT) + '</p></div></div>'
}
//]]>
</script>
Then my variable, each post have single variable, different for each post based on it's ID:
<script type='text/javascript'>var x="Post Title",y="http://myblog.url/post-url.html";rm("p8304387062855771110")
My single post markup:
<span id='p8304387062855771110'></span>
The problem is, the append function in my script not work. Am I forget something in my code?
Your jQuery/JavaScript is very ropey. There is no method each on a nodelist. Try not to mix jQuery/JavaScript up so much. And you might consider using a array/join on the html you want to insert to keep the line length readable. That way you might have noticed that your HTML quotes were not consistent.1
var $p = $('#' + a);
$p.find('img').each(function () {
var html = $('<li>').append($(this))
$('.flexslider .slides').append(html);
});
var html = [
'<div class="entry-container"><div class="entry-content">',
'<div class="entry-image"><div class="flexslider">',
'<ul class="slides"></ul></div></div><div class="entry-header">',
'<h1><a href="',
y,
'">',
x,
'</a></h1></div><p>',
stripTags(p.innerHTML, SNIPPET_COUNT),
'</p></div></div>'
].join('');
$p.html(html);
1 Personally I prefer single quotes for JS work and double quotes for HTML attributes and never the twain shall meet.
I think <li> doesnt work try li like this:
$(".flexslider .slides").append($("li").append(this));
You could get rid of type="text/javascript" and //<![CDATA[, it is 2014, after all ;-)
Also, .*? is not what you mean.
<script>
function stripTags(s, n) {
return s.replace(/<[^>]*>/g, "") // Be careful with .*? : it is not correct
.split(/\s+/)
.slice(0, n - 1)
.join(" ")
}
function rm(id) {
var $p = $('#' + id);
img = $p.find("img").each( function(){
$(".flexslider .slides").append($("<li>").append(this));
});
p.innerHTML = '<div class="entry-container"><div class="entry-content"><div class="entry-image"><div class="flexslider"><ul class="slides"></ul></div></div><div class="entry-header"><h1>' + x + '</h1></div><p>' + stripTags(p.innerHTML, SNIPPET_COUNT) + '</p></div></div>'
}
</script>

Substitute specific letters in document with spans

Let's say I have the following HTML code
<div class="answers">
He<b>y</b> <span class='doesntmatter'>eve</span>ryone
</div>
And I have the following array:
['correct','correct','incorrect','correct','correct','correct','incorrect','incorrect','correct','correct','incorrect']
I want to transform this piece of HTML code, and add a span to each letter with the class in the array (I'll explain)
So, I want to transform the letter H to say <span class='correct'>H</span>
e to say: <span class='correct'>e</span>
y to say: <span class='incorrect'>y</span>
e to say: <span class='correct'>e</span>
And so on. I want to make sure to keep the original HTML, <br> tags, <p> tags and the such. I can't use jQuery(element).text() for this reason (since it breaks the tags).
Anyone has an idea how I would do this? It's much appreciated.
var arr = ['correct','correct','incorrect','correct','correct','correct','incorrect','incorrect','correct','correct','incorrect'],
answer = document.getElementsByClassName("answers")[0],
rex = /(?=\w|<)(?=[^>]*(?:<|$))/,
i = 0, class;
answer.innerHTML = answer.innerHTML.split(rex).map(function(p) {
if (p.indexOf('>')) return p;
class = arr[i++] || 'notDefined';
return '<span class="' + class + '">' + p + '</span>';
}).join('');
Non-word characters are not wrapped. If the text contains html-entities (e.g ) there will be some extra effort.
How about this:
http://jsfiddle.net/bn777pky/
The jQuery needs refined but it's not my strong suit.
HTML
<div class="numbers">123456789</div>
CSS
.correct {
color: red
}
.incorrect {
color: blue;
}
Jquery
$(".numbers").each(function (index) {
var characters = $(this).text().split("");
$this = $(this);
$this.empty();
$.each(characters, function (i, el) {
$this.append("<span>" + el + "</span");
});
$("span").each( function (index) {
index += 1;
if(index % 3 == 0) {
$(this).addClass("incorrect");
}
else {
$(this).addClass("correct");
}
});
});

case insensitive word boundaries with regExp

for some reason the gi modifier is behaving as case sensitive. Not sure what's going on, but maybe someone knows why this is. it works fine when the cases are the same. This JSFiddle will demonstrate my problem. Code below. Thanks.
javaScript:
var search_value = $('#search').val();
var search_regexp = new RegExp(search_value, "gi");
$('.searchable').each(function(){
var newText =(this).html().replace(search_value, "<span class = 'highlight'>" + search_value + "</span>");
$(this).html(newText);
});
HTML:
<input id = "search" value = "Red">
<div class = "searchable">this should be red</div>
<div class = "searchable">this should be Red</div>
Correct Code is
var search_value = $('#search').val();
var search_regexp = new RegExp(search_value, "gi");
$('.searchable').each(function(){
// var newText =$(this).html().replace(search_value, "<span class = 'highlight'>" + search_value + "</span>");
var newText =$(this).html().replace(search_regexp, function(matchRes) {
return "<span class = 'highlight'>" + matchRes + "</span>";
});
$(this).html(newText);
});
output
Fiddle
Issues with your code:-
First: search_regexp - You haven't used search_regexp anywhere in your code
Your Code
var newText =$(this).html().replace(search_value, "<span class = 'highlight'>" + search_value + "</span>");
Second
You are using search_value to replace. It will make both Red and red to either Red or red after replace.
eg: if search_value is Red then your output will be
this should be Red
this should be Red
you should use matched result instead of search_value
Third: How to use RegExp with replace function?
Correct Method is
var newText =$(this).html().replace(search_regexp, function(matchRes) {
return "<span class = 'highlight'>" + matchRes + "</span>";
});
Explanation
replace(<RegEx>, handler)
Your code isn't using your regex in the replace call, it's just using the search_value. This JSBin shows your code working: http://jsbin.com/toquz/1/
Do you actually want to replace the matches with the value (changing lowercase instances to uppercase in this example)? Using $.html() will also get you any markup within that element, so keep that in mind as well (in case there's a chance of having markup in the .searchable elements along with text.
Might be easier to do:
function highlight(term) {
var search_regexp = new RegExp(term, "gi");
$('.searchable').each(function(){
if (search_regexp.test($(this).html())) {
var highlighted = $(this).html().replace(search_regexp, function(m) {
return '<span class="highlight">'+m+'</span>';
});
$(this).html(highlighted);
}
});
}
Your original code in the JSBin is the highlightReplace() function.

Categories

Resources