Javascript regex code not working as expected - javascript

I made a function to break a string to break it into parts.
I read on MDN that by putting regex in parentheses I could refer it later by using $1 but for some reason my code is not working.
I want this function to return 'url this' but it is return '$ 1his'.
Please Help!
const someFunction = str => {
return str.replace(/([A-Z]+)/g,('$1'.slice(0,-1).toLowerCase() + ' ' + '$1'.slice(-1).toLowerCase()));
}
console.log(someFunction('URLThis'))

You can pass function in the second parameter to string#replace.
const someFunction = str => {
return str.replace(/[A-Z]+/g, (match) => {
return match.slice(0,-1).toLowerCase() + ' ' + match.slice(-1).toLowerCase();
});
}
console.log(someFunction('URLThis'))

You are going to want to use a function as the second parameter for manipulating the result of the replacement. From MDN String.prototype.replace():
Because we want to further transform the result of the match before
the final substitution is made, we must use a function. This forces
the evaluation of the match prior to the toLowerCase() method. If we
had tried to do this using the match without a function, the
toLowerCase() would have no effect.
This is because '$&'.toLowerCase() would be evaluated first as a
string literal (resulting in the same '$&') before using the
characters as a pattern.

Related

Replace multiple strings containing $ sign

I face a problem with regex and string replace and I would love a little bit of help.
I have a string with the following format
<div class="$(unique-result) single-result data-index=$(i)"><div class="airport-data data-index=$(i)">$(name)<br>$(city) ,$(country)</div><div class="airport-code data-index=$(i)">$(IATA)</div></div>
and I need to replace all the $(unique-result) with a string of mine.
I tried the following code but I can't seem to find out why this doesn't work
string.replace(new RegExp('\\$(unique-result)', 'g'), changeString)
The result is the exact same string I gave as an input.
Could anyone help me out but also point out why it didn't work?
Thank you in advance.
You missed escaping. you need to escape properly
let str = `<div class="$(unique-result) single-result data-index=$(i)"><div class="airport-data data-index=$(i)">$(name)<br>$(city) ,$(country)</div><div class="airport-code data-index=$(i)">$(IATA)</div></div>`
let op = str.replace(new RegExp('\\$\\(unique-result\\)','g'), 'Changed')
console.log(op)
In case i am not using any variable i prefer using regex literal (//)
let str = `<div class="$(unique-result) single-result data-index=$(i)"><div class="airport-data data-index=$(i)">$(name)<br>$(city) ,$(country)</div><div class="airport-code data-index=$(i)">$(IATA)</div></div>`
let op = str.replace(/\$\(unique-result\)/g, 'Changed')
console.log(op)
There is more general solution.
First of all, as I mentioned in comments, you don't need to use the RegExp constructor, you can simply pass your regexp between slashes and use flags after last slash:
str.replace(/\$\(unique-result\)/g, "someValue")
The second moment is that String.prototype.replace can accept a function as a second parameter. This will be helpful when there is a lot of named templates in you string. For example, you have the next incoming string:
var incomingString = "$(first-value) says $(second-value) when there is $(third-value)"
With code that you've provided you should call replace 3 times. But if you will use a function as a second parameter, this can be simplified to:
var incomingString = "$(first-value) says $(second-value) when there is $(third-value)"
var data = {
"first-value": "Kappa",
"second-value": "Hey!",
"third-value": "GreyFaceNoSpace"
}
var resultString = incomingString.replace(/\$\(([^)]+)\)/g, (match, capture) => {
console.log(match, capture)
return data[capture]
})
console.log(resultString)
"WHAT IS GOING ON HERE?!" you will probably ask. Nothing complex.
Function that is passed as argument accepts one or more arguments: first is a full match and the others are captured groups. It should return the string, that should replace the full match.
In our regular expression we described that we want to match all possible substrings in format \$\(([^)]+)\), where [^)]+ refers to one-or-more-of-any-symbols-except-a-closing-bracket, and this construction should be captured (it is between not-sanitized brackets).
So, once this regexp will match, it will pass the whole $(...) construction into match argument of passed function, and the name of the template into capture argument. So capture is our key for some data storage and we just returning this value in the function.
That's it! Hope, this will be helpful :)
You can use a simple function to make the substitution. Match every $(string) and apply a function to replace it with a variable stored in an object. Easy and extensible.
const tpl = '<div class="$(unique-result) single-result data-index=$(i)"><div class="airport-data data-index=$(i)">$(name)<br>$(city) ,$(country)</div><div class="airport-code data-index=$(i)">$(IATA)</div></div>';
const vars = {
i : 9,
'unique-result' : 'uniq',
country : 'gb',
city : 'Manchester',
IATA : 'MCH'
};
const replaceVars = (tpl,vars) => {
const replacer = (m, m1) =>
typeof vars[m1] != 'undefined' ? vars[m1] : '';
return tpl.replace(/\$\(([\w-]+)\)/g, replacer);
};
console.log(replaceVars(tpl,vars));

Convert slug variable to title text with javascript

I'm trying to do something that would be similar to turning a url slug-like variable into text that could be used for a title.
So, I have a variable for example that is like this:
var thisID = 'athlete-profile';
function myFunc(thisID) {
// i need to use thisID as the id and href in a loop that generates a string of <li><a>'s\
function makeTitle(thisID) {
// convert thisID to text so for this example it would return 'Athlete Profile'
return 'Athlete Profile';
}
for () {
var str = '<li id="'+thisID+'">'+makeTitle(thisID)+'';
}
// make sense?
}
I'd like to not use a regex to do this if possible somehow, but I don't think there's a way to do it without one. So any one who knows how to do this type of thing let me know, it would be a great help.
Thanks
I would advise you to use regular expression. But if you really don't want to use regular expressions, the solution below would work for simple cases. Feel free to modify it as you like it.
function makeTitle(slug) {
var words = slug.split('-');
for (var i = 0; i < words.length; i++) {
var word = words[i];
words[i] = word.charAt(0).toUpperCase() + word.slice(1);
}
return words.join(' ');
}
console.log(
makeTitle("athlete-profile")
)
function titleize(slug) {
var words = slug.split("-");
return words.map(function(word) {
return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();
}).join(' ');
}
console.log(titleize("athlete-profile"))
It works pretty simply:
It splits the string by - into words.
It maps each word into title case.
It joins the resulting words with spaces.
Do it in one line:
'athlete-profile'.split("-").join(" ").replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()})
Output: Athlete Profile
The makeTitle() part of your question can be implemented something like this:
function makeTitle(thisID) {
return thisID.replace(/-/g, " ").replace(/\b[a-z]/g, function() {
return arguments[0].toUpperCase();
});
}
console.log(makeTitle("athlete-profile"))
The first .replace() changes all hyphens to spaces, and then the second .replace() takes any lower-case letter that follows a word boundary and makes it upper-case.
(For more information see the MDN doco for .replace().)
As far as doing it without using regular expressions, I'm not sure why you'd specifically want to avoid them, especially when the required expressions are pretty simple in this case (especially if you do the hyphen to space and first letter capitalisation in two steps as shown above). But there are endless ways to do this without regex using various combinations of JavaScript's string manipulation methods.
Do it like this
let someString = 'im a string';
console.log(someString.replace(/-/g, ' ')
.replace(/\w\S*/g, function (txt) {
return
txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
})
)
Output: Im A String
Short and great way:
const slugToText = (slug) => {
return slug.toLowerCase().replace(/-/g,' ')
}
Much Simplified answer
we can use String.prototype.replaceAll method to easily achieve this
function convertSlugToString(slug) {
return slug.replaceAll("-", " ");
}
incase you want to make sure the output is all lowercase then you can do the following
function convertSlugToString(slug) {
return slug.toLowerCase().replaceAll("-", " ");
}
Additional info:
String.prototype.replaceAll() is a ES2021 feature and it also has a great browser support with 93.64% global coverage, click here for more info
if you want to support IE then refer to the other answers

How to know if JavaScript string.replace() did anything?

The replace function returns the new string with the replaces, but if there weren't any words to replace, then the original string is returned. Is there a way to know whether it actually replaced anything apart from comparing the result with the original string?
A simple option is to check for matches before you replace:
var regex = /i/g;
var newStr = str;
var replaced = str.search(regex) >= 0;
if(replaced){
newStr = newStr.replace(regex, '!');
}
If you don't want that either, you can abuse the replace callback to achieve that in a single pass:
var replaced = false;
var newStr = str.replace(/i/g, function(token){replaced = true; return '!';});
As a workaround you can implement your own callback function that will set a flag and do the replacement. The replacement argument of replace can accept functions.
Comparing the before and after strings is the easiest way to check if it did anything, there's no intrinsic support in String.replace().
[contrived example of how '==' might fail deleted because it was wrong]
Javascript replace is defected by design. Why? It has no compatibility with string replacement in callback.
For example:
"ab".replace(/(a)(b)/, "$1$2")
> "ab"
We want to verify that replace is done in single pass. I was imagine something like:
"ab".replace(/(a)(b)/, "$1$2", function replacing() { console.log('ok'); })
> "ab"
Real variant:
"ab".replace(/(a)(b)/, function replacing() {
console.log('ok');
return "$1$2";
})
> ok
> "$1$2"
But function replacing is designed to receive $0, $1, $2, offset, string and we have to fight with replacement "$1$2". The solution is:
"ab".replace(/(a)(b)/, function replacing() {
console.log('ok');
// arguments are $0, $1, ..., offset, string
return Array.from(arguments).slice(1, -2)
.reduce(function (pattern, match, index) {
// '$1' from strings like '$11 $12' shouldn't be replaced.
return pattern.replace(
new RegExp("\\$" + (index + 1) + "(?=[^\\d]|$)", "g"),
match
);
}, "$1$2");
});
> ok
> "ab"
This solution is not perfect. String replacement itself has its own WATs. For example:
"a".replace(/(a)/, "$01")
> "a"
"a".replace(/(a)/, "$001")
> "$001"
If you want to care about compatibility you have to read spec and implement all its craziness.
If your replace has a different length from the searched text, you can check the length of the string before and after. I know, this is a partial response, valid only on a subset of the problem.
OR
You can do a search. If the search is successfull you do a replace on the substring starting with the found index and then recompose the string. This could be slower because you are generating 3 strings instead of 2.
var test = "Hellllo";
var index = test.search(/ll/);
if (index >= 0) {
test = test.substr(0, index - 1) + test.substr(index).replace(/ll/g, "tt");
}
alert(test);
While this will require multiple operations, using .test() may suffice:
const regex = /foo/;
const yourString = 'foo bar';
if (regex.test(yourString)) {
console.log('yourString contains regex');
// Go ahead and do whatever else you'd like.
}
The test() method executes a search for a match between a regular expression and a specified string. Returns true or false.
With indexOf you can check wether a string contains another string.
Seems like you might want to use that.
have a look at string.match() or string.search()
After doing any RegExp method, read RegExp.lastMatch property:
/^$/.test(''); //Clear RegExp.lastMatch first, Its value will be ''
'abcd'.replace(/bc/,'12');
if(RegExp.lastMatch !== '')
console.log('has been replaced');
else
console.log('not replaced');

Cross-Browser Regular expression library for Javascript to replace using function

Is there a library for replacing using functions as argument
when I call this function
"foo[10]bar[20]baz".replacef(/\[([0-9]*)\]/g, function(a) {
return '[' + (ParseInt(a)*10) + ']';
});
it should return
"foo[20]bar[30]baz";
and when I call with this
"foo[10;5]bar[15;5]baz".replacef(/\[([0-9]*);([0-9]*)\]/g, function(a, b) {
return '_' + (ParseInt(a)+ParseInt(b)) + '_';
});
it should return
"foo_15_bar_20_baz"
Is there existing Cross-Browser library that have function like this or similar in JavaScript?
That's how the "replace()" function already works. If the second parameter is a function, it's passed a list of arguments that are pretty much the same as the array returned from the RegExp "exec()" function. The function returns what it wants the matched region to be replaced with.
The first argument to the called function is the whole matched string. The second and subsequent arguments are the captured groups from the regex (like your second example). Your second example, however, would need a function with one more parameter to hold the entire matched string.
Example:
var s = "hello world".replace(/(\w+)\s*(\w+)/, function(wholeMatch, firstWord, secondWord) {
return "first: " + firstWord + " second: " + secondWord;
});
alert(s); // "first: hello second: world"
As far as I know you can readily do something like this in javascript :
"foo[10]bar[20]baz".replace(/\[([0-9]+)\]/g, function() {
return '[' + (parseInt(arguments[1])*10) + ']';
});
This is afaik cross browser (notice that parseInt got no leading uppercase p), arguments contains the match, index 0 is the whole thing, 1 and so on are the captured groups.

Javascript regexp: replacing $1 with f($1)

I have a regular expression, say /url.com\/([A-Za-z]+)\.html/, and I would like to replace it with new string $1: f($1), that is, with a constant string with two interpolations, the captured string and a function of the captured string.
What's the best way to do this in JavaScript? 'Best' here means some combination of (1) least error-prone, (2) most efficient in terms of space and speed, and (3) most idiomatically appropriate for JavaScript, with a particular emphasis on #3.
The replace method can take a function as the replacement parameter.
For example:
str.replace(/regex/, function(match, group1, group2, index, original) {
return "new string " + group1 + ": " + f(group1);
});
When using String.replace, you can supply a callback function as the replacement parameter instead of a string and create your own, very custom return value.
'foo'.replace(/bar/, function (str, p1, p2) {
return /* some custom string */;
});
.replace() takes a function for the replace, like this:
var newStr = string.replace(/url.com\/([A-Za-z]+)\.html/, function(all, match) {
return match + " something";
});
You can transform the result however you want, just return whatever you want the match to be in that callback. You can test it out here.

Categories