variable array + regular expression not working together? - javascript

im making a small smiley script , what it does is to change ::1:: into an image html for a div.
the code as follow:
var smileys = {
'1': 'http://domain.com/smiley1.gif',
'2': 'http://domain.com/smiley2.gif',
'3': 'http://domain.com/smiley3.gif'
};
function checksmileys(){
x$('.message').each(function()
var start = '<img src="';
var end = '">';
x$(this).html( x$(this).html().replace(/::(\d+)::/g, start + smileys['$1'] + end) );
});
Checksmileys function is triggered by user event.
However it is not able to get the digit(which is the id) out of a sentence.
It kept on producing this <img src="undefined">
My HTML example as follows:
<div id="chat">
<ul>
<li class="message">Hi john</li>
<li class="message">what are you doing</li>
<li class="message">::1:: nothing</li>
<li class="message">hi</li>
<li class="message">nice to meet you ::1::</li>
</ul>
</div>
Where is my problem here?

I guess you need a function here:
html = html.replace(/::(\d+)::/g, function($0, $1) { return start + smileys[$1] + end })
here's when the functional form of html() comes in handy
$(this).html(function(_, oldhtml) {
return oldhtml.replace(/::(\d+)::/g, function($0, $1) {
return start + smileys[$1] + end;
})
})

In JavaScript, property names don't have prefixes like they often do in PHP. The name of the property you create in your smileys object is 1, not $1, so change smileys['$1'] to smileys['1'].
Update: From your comment below, it seems you're trying to use $1 to refer to the capture group. That only works when $1 is part of the string you pass in, but the expression start + smileys['$1'] + end is evaluated before the call to replace and then passed into it. smileys['$1'] will be undefined.
Since you're trying to do a lookup, your best bet is to pass in a function that does the lookup:
x$(this).html( x$(this).html().replace(/::(\d+)::/g, function(m, c1) {
return start + smileys[c1] + end;
}) );
c1 is the text of the first capture group. More
You've called it an array, which I'm guessing is because you're used to the term "associative array" from PHP. Your smileys object is just an object, not an array. In JavaScript, when we say "array", we mean something created via [] or new Array, which has specific handling for a certain class of property names (numeric ones), a special length property, and some handy array-like functions. What you've done with smileys is perfectly fine and completely normal, we just tend not to use the word "array" for it ("map" is more common in the JS world).

Related

Look for substring in a string with at most one different character-javascript

I am new in programing and right now I am working on one program. Program need to find the substring in a string and return the index where the chain starts to be the same. I know that for that I can use "indexOf". Is not so easy. I want to find out substrings with at moste one different char.
I was thinking about regular expresion... but not really know how to use it because I need to use regular expresion for every element of the string. Here some code wich propably will clarify what I want to do:
var A= "abbab";
var B= "ba";
var tb=[];
console.log(A.indexOf(B));
for (var i=0;i<B.length; i++){
var D=B.replace(B[i],"[a-z]");
tb.push(A.indexOf(D));
}
console.log(tb);
I know that the substring B and string A are the lowercase letters. Will be nice to get any advice how to make it using regular expresions. Thx
Simple Input:
A B
1) abbab ba
2) hello world
3) banana nan
Expected Output:
1) 1 2
2) No Match!
3) 0 2
While probably theoretically possible, I think it would very complicated to try this kind of search while attempting to incorporate all possible search query options in one long complex regular expression. I think a better approach is to use JavaScript to dynamically create various simpler options and then search with each separately.
The following code sequentially replaces each character in the initial query string with a regular expression wild card (i.e. a period, '.') and then searches the target string with that. For example, if the initial query string is 'nan', it will search with '.an', 'n.n' and 'na.'. It will only add the position of the hit to the list of hits if that position has not already been hit on a previous search. i.e. It ensures that the list of hits contains only unique values, even if multiple query variations found a hit at the same location. (This could be implemented even better with ES6 sets, but I couldn't get the Stack Overflow code snippet tool to cooperate with me while trying to use a set, even with the Babel option checked.) Finally, it sorts the hits in ascending order.
Update: The search algorithm has been updated/corrected. Originally, some hits were missed because the exec search for any query variation would only iterate as per the JavaScript default, i.e. after finding a match, it would start the next search at the next character after the end of the previous match, e.g. it would find 'aa' in 'aaaa' at positions 0 and 2. Now it starts the next search at the next character after the start of the previous match, e.g. it now finds 'aa' in 'aaaa' at positions 0, 1 and 2.
const findAllowingOneMismatch = (target, query) => {
const numLetters = query.length;
const queryVariations = [];
for (let variationNum = 0; variationNum < numLetters; variationNum += 1) {
queryVariations.push(query.slice(0, variationNum) + "." + query.slice(variationNum + 1));
};
let hits = [];
queryVariations.forEach(queryVariation => {
const re = new RegExp(queryVariation, "g");
let myArray;
while ((searchResult = re.exec(target)) !== null) {
re.lastIndex = searchResult.index + 1;
const hit = searchResult.index;
// console.log('found a hit with ' + queryVariation + ' at position ' + hit);
if (hits.indexOf(hit) === -1) {
hits.push(searchResult.index);
}
}
});
hits = hits.sort((a,b)=>(a-b));
console.log('Found "' + query + '" in "' + target + '" at positions:', JSON.stringify(hits));
};
[
['abbab', 'ba'],
['hello', 'world'],
['banana', 'nan'],
['abcde abcxe abxxe xbcde', 'abcd'],
['--xx-xxx--x----x-x-xxx--x--x-x-xx-', '----']
].forEach(pair => {findAllowingOneMismatch(pair[0], pair[1])});

AngularJS bind and replace text [duplicate]

I'm new to AngularJS and trying to create a simple app that will allow me to upload files to my Laravel driven website. I want the form to show me the preview of what the uploaded item will look like. So I am using ng-model to achieve this and I have stumbled upon the following:
I have an input with some basic bootstrap stylings and I am using custom brackets for AngularJS templating (because as I mentioned, I am using Laravel with its blading system). And I need to remove spaces from the input (as I type it) and replace them with dashes:
<div class="form-group"><input type="text" plaeholder="Title" name="title" class="form-control" ng-model="gnTitle" /></div>
And then I have this:
<a ng-href="/art/[[gnTitle | spaceless]]" target="_blank">[[gnTitle | lowercase]]</a>
And my app.js looks like this:
var app = angular.module('neoperdition',[]);
app.config(function($interpolateProvider){
$interpolateProvider.startSymbol('[[').endSymbol(']]');
});
app.filter('spaceless',function(){
return function(input){
input.replace(' ','-');
}
});
I get the following error:
TypeError: Cannot read property 'replace' of undefined
I understand that I need to define the value before I filter it, but I'm not sure where to define it exactly. And also, if I define it, I don't want it to change my placeholder.
There are few things missing in your filter. First of all you need to return new string. Secondary, regular expression is not correct, you should use global modifier in order to replace all space characters. Finally you also need to check if the string is defined, because initially model value can be undefined, so .replace on undefined will throw error.
All together:
app.filter('spaceless',function() {
return function(input) {
if (input) {
return input.replace(/\s+/g, '-');
}
}
});
Demo: http://plnkr.co/edit/5Rd1SLjvNI18MDpSEP0a?p=preview
Bravi just try this filter
for eaxample {{X | replaceSpaceToDash}}
app.filter('replaceSpaceToDash', function(){
var replaceSpaceToDash= function( input ){
var words = input.split( ' ' );
for ( var i = 0, len = words.length; i < len; i++ )
words[i] = words[i].charAt( 0 ) + words[i].slice( 1 );
return words.join( '-' );
};
return replaceSpaceToDash;
});
First, you have to inject your filter in you module by adding it's name to the array :
var app = angular.module('neoperdition',['spaceless']);
Secondly, the function of the filter have to return something. The String.prototype.replace() return a new String. so you have to return it :
app.filter('spaceless',function(){
return function(input){
return input.replace(' ','-');
}
});
Edit: dfsq's answer being a lot more accurate than mine.

Calculation within Regular Expression

I had a crazy idea.
I want to do a calculation within a regular expression but I'm not sure if it's possible. Basically I have a line that says:
Category:
And every time you click a button it will say:
Category:
Category 1:
Category 2:
etc. I am doing a string of functions on a jQuery selector right now as such:
var newHTML = selector.closest('.row').clone().html().replace(/(Category)(\s)(\d)/g,'$1$2' + (parseInt('$3') + 1)).replace('Category:','Category 2:');
So it does the first replace and if it's the original 'Category' it won't match and will run the second replace. If it does match, I want it to increment the number on the end of the expression by one. I thought maybe I could parseInt() the variable and add one but that doesn't work since parseInt('$3') appears to return NaN and doesn't recognize the variable as an integer.
I know there are plenty of other ways to do this but I just stumbled across it, stumped myself and always like to find any answer to a good question...
Any thoughts? Thanks!
Like in many other languages, JavaScript evaluates the arguments before they are passed to the function. So in your case '$1$2' + (parseInt('$3') + 1)) is evaluated first, which results in the string '$1$2NaN', and that is passed to .replace. parseInt('$3') is NaN because the string '$3' cannot be converted to a number:
> parseInt('$3')
NaN
If you want to perform any computation with the matches, you have to pass a function as second argument:
.replace(/(Category)(\s)(\d)/g, function(match, $1, $2, $3) {
return $1 + $2 + (parseInt($3) + 1));
})
(of course you can name the arguments whatever you want)
You can learn more about passing callbacks to .replace in the MDN documentation.
Further to #FelixKling's answer here is a working demo, just to show what adjustment you might have make.
$('.cat').on('click', function() {
$(this).html(function(i,html) {
return html.replace(/(Category)(\s?)(\d*)/g, function(match, x, y, z) {
y = y || ' ';
z = z || 0;
return x + y + (+z + 1);
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="cat">Category</div>
<div class="cat">Goint with Category Blah Blah Blah</div>

Dojo Toolkit: how to escape an HTML string?

A user of my HTML 5 application can enter his name in a form, and this name will be displayed elsewhere. More specifically, it will become the innerHTML of some HTML element.
The problem is that this can be exploited if one enters valid HTML markup in the form, i.e. some sort of HTML injection, if you will.
The user's name is only stored and displayed on the client side so in the end the user himself is the only one who is affected, but it's still sloppy.
Is there a way to escape a string before I put it in an elements innerHTML in Dojo? I guess that Dojo at one point did in fact have such a function (dojo.string.escape()) but it doesn't exist in version 1.7.
Thanks.
dojox.html.entities.encode(myString);
Dojo has the module dojox/html/entities for HTML escaping. Unfortunately, the official documentation still provides only pre-1.7, non-AMD example.
Here is an example how to use that module with AMD:
var str = "<strong>some text</strong>"
require(['dojox/html/entities'], function(entities) {
var escaped = entities.encode(str)
console.log(escaped)
})
Output:
<strong>some text</strong>
As of Dojo 1.10, the escape function is still part of the string module.
http://dojotoolkit.org/api/?qs=1.10/dojo/string
Here's how you can use it as a simple template system.
require([
'dojo/string'
], function(
string
){
var template = '<h1>${title}</h1>';
var message = {title: 'Hello World!<script>alert("Doing something naughty here...")</script>'}
var html = string.substitute(
template
, message
, string.escape
);
});
I tried to find out how other libraries implement this function and I stole the idea of the following from MooTools:
var property = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
elem[property] = "<" + "script" + ">" + "alert('a');" + "</" + "script" + ">";
So according to MooTools there is either the innerText or the textContent property which can escape HTML.
Check this example of dojo.replace:
require(["dojo/_base/lang"], function(lang){
function safeReplace(tmpl, dict){
// convert dict to a function, if needed
var fn = lang.isFunction(dict) ? dict : function(_, name){
return lang.getObject(name, false, dict);
};
// perform the substitution
return lang.replace(tmpl, function(_, name){
if(name.charAt(0) == '!'){
// no escaping
return fn(_, name.slice(1));
}
// escape
return fn(_, name).
replace(/&/g, "&").
replace(/</g, "<").
replace(/>/g, ">").
replace(/"/g, """);
});
}
// that is how we use it:
var output = safeReplace("<div>{0}</div",
["<script>alert('Let\' break stuff!');</script>"]
);
});
Source: http://dojotoolkit.org/reference-guide/1.7/dojo/replace.html#escaping-substitutions

Efficient Javascript String Replacement

Hey there, I've got a block of HTML that I'm going to be using repeatedly (at various times during a users visit, not at once). I think that the best way to accomplish this is to create an HTML div, hide it, and when needed take its innerHTML and do a replace() on several keywords. As an example HTML block...
<div id='sample'>
<h4>%TITLE%</h4>
<p>Text text %KEYWORD% text</p>
<p>%CONTENT%</p>
<img src="images/%ID%/1.jpg" />
</div>
Would the best way to replace those keywords with dynamic data be to go...
template = document.getElementById('sample');
template = template.replace(/%TITLE%/, some_var_with_title);
template = template.replace(/%KEYWORD%/, some_var_with_keyword);
template = template.replace(/%CONTENT%/, some_var_with_content);
template = template.replace(/%ID%/, some_var_with_id);
It just feels like I've chosen a stupid way to do this. Does anyone have any suggestions on how to do this faster, smarter, or better in any way? This code will be executed fairly often during a users visit, sometimes as often as once every 3-4 seconds.
Thanks in advance.
It looks like you want to use a template.
//Updated 28 October 2011: Now allows 0, NaN, false, null and undefined in output.
function template( templateid, data ){
return document.getElementById( templateid ).innerHTML
.replace(
/%(\w*)%/g, // or /{(\w*)}/g for "{this} instead of %this%"
function( m, key ){
return data.hasOwnProperty( key ) ? data[ key ] : "";
}
);
}
Explanation of the code:
Expects templateid to be the id of an existing element.
Expects data to be an object with the data.
Uses two parameters to replace to do the substitution:
The first is a regexp that searches for all %keys% (or {keys} if you use the alternate version). The key can be a combination of A-Z, a-z, 0-9 and underscore _.
The second is a anonymous function that gets called for every match.
The anonymous function searches the data object for the key that the regexp found.
If the key is found in the data, then the value of the key is returned and that value will be replacing the key in the final output. If the key isn't found, an empty string is returned.
Example of template:
<div id="mytemplate">
<p>%test%</p>
<p>%word%</p>
</div>
Example of call:
document.getElementById("my").innerHTML=template("mytemplate",{test:"MYTEST",word:"MYWORD"});
You could probably adapt this code to do what you want:
let user = {
"firstName": "John",
"login": "john_doe",
"password": "test",
};
let template = `Hey {firstName},
You recently requested your password.
login: {login}
password: {password}
If you did not request your password, please disregard this message.
`;
template = template.replace(/{([^{}]+)}/g, function(keyExpr, key) {
return user[key] || "";
});
You might also want to look into JavaScriptTemplates
Template Replacement
A quick and easy solution will be to use the String.prototype.replace method.It takes a second parameter that can be either a value or a function:
function replaceMe(template, data) {
const pattern = /{\s*(\w+?)\s*}/g; // {property}
return template.replace(pattern, (_, token) => data[token] || '');
}
###Example:
const html = `
<div>
<h4>{title}</h4>
<p>My name is {name}</p>
<img src="{url}" />
</div>
`;
const data = {
title: 'My Profile',
name: 'John Smith',
url: 'http://images/john.jpeg'
};
And call it like so:
replaceMe(html, data);
I doubt there will be anything more efficient. The alternative would be splitting it into parts and then concatenating, but I don't think that would be much efficient. Perhaps even less, considering that every concatenation results in a new string which has the same size as its operands.
Added: This is probably the most elegant way to write this. Besides - what are you worried about? Memory usage? It's abundant and Javascript has a decent memory manager. Execution speed? Then you must have some gigantic string. IMHO this is good.
Your method is a standard way to implement a poor-man's templating system, so it's fine.
It could be worth your while to check out some JavaScript templating libraries, such as JST.
You can make it more efficient by chaining the replaces instead of making all these interim assignments.
i.e.
with(document.getElementById('sample'))
{
innerHTML = innerHTML.replace(a, A).replace(b, B).replace(c, C); //etc
}
If you're willing to use the Prototype library, they have nice built in templating functionality.
That would look like:
element.innerHTML = (new Template(element.innerHTML)).evaluate({
title: 'a title',
keyword: 'some keyword',
content: 'A bunch of content',
id: 'id here'
})
This would be especially nice if you were running your code in a loop due to the ease of creating JSON objects/Javascript object literals.
Still, I wouldn't expect any speed increase.
Also, you would need to change your delimiter style to #{keyword} rather than %keyword%
This approach generates function templates that can be cached:
function compileMessage (message) {
return new Function('obj', 'with(obj){ return \'' +
message.replace(/\n/g, '\\n').split(/{{([^{}]+)}}/g).map(function (expression, i) {
return i%2 ? ( '\'+(' + expression.trim() + ')+\'' ) : expression;
}).join('') +
'\'; }');
}
var renderMessage = compileMessage('Hi {{ recipient.first_name }},\n\n' +
'Lorem ipsum dolor sit amet...\n\n' +
'Best Regarts,\n\n' +
'{{ sender.first_name }}');
renderMessage({
recipient: {
first_name: 'John'
},
sender: {
first_name: 'William'
}
});
returns:
"Hi John,
Lorem ipsum dolor sit amet...
Best Regarts,
William"
Mustachejs is great for really elegant templating:
<div id='sample'>
<h4>{{TITLE}}</h4>
<p>Text text {{KEYWORD}} text</p>
<p>{{CONTENT}}</p>
<img src="images/{{ID}}/1.jpg" />
</div>
You can then use the template something like this:
var template = document.getElementById(templateid).innerHTML;
var newHtml = Mustache.render(template, {
TITLE: some_var_with_title,
KEYWORD: some_var_with_keyword,
CONTENT: some_var_with_content,
ID: some_var_with_id
});
document.getElementById('sample').innerHTML = newHtml;
This especially works nicely if you are getting JSON back from an Ajax call - you can just pass it straight in to the Mustache.render() call.
Slight variations allow for running the same template on each the browser or the server. See https://github.com/janl/mustache.js for more details.
Try this: http://json2html.com/
It supports complex JSON objects as well.
In 2023 all modern browsers have JavaScript ES6 (ECMAScript 2015) with built-in template literals with replacement functionality. There is no longer a need to use external libraries or regex unless you need to support IE: https://caniuse.com/?search=template%20literals
Basic usage:
Template literals start and end with backticks `
Replacement values enclosed like so ${value} where value is a JS expression.
Added benefits: no need to escape single or double quote characters and newlines are preserved.
See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
// Generate HTML markup for XYZ page
// #param {object} obj - parameter object with replacement values
function getMyHtml(obj) {
if (!obj) return "";
return `<div id='sample'>
<h4>${obj.title}</h4>
<p>Text text ${obj.keyword} text</p>
<p>${obj.content}</p>
<img src="https://live.staticflickr.com/${obj.id}/52313050555_c70c17a288_m.jpg" />
</div>`
}
// example usage:
document.getElementById('container').innerHTML = getMyHtml({
title: 'Cellular Base Stations in Orbit',
keyword: 'SpaceX',
content: 'Tonight’s unveil: Connecting directly...',
id: 65535
});
<div id='container' style='border: 1px solid blue;'>
</div>
(example links to a flickr photo by Steve Jurvetson)
var template = "<div id='sample'><h4>%VAR%</h4><p>Text text %VAR% text</p><p>%VAR%</p><img src="images/%VAR%/1.jpg" /></div>";
var replace = function(temp,replace){
temp = temp.split('%VAR%');
for(var i in replace){
if(typeof temp[i] != 'undefined'){
temp[i] = temp[i] + replace[i];
}
}
return temp.join('');
}
replace(template,['title','keyword','content','id'])

Categories

Resources