I want to create a regex with following logic:
1., If string contains T replace it with space
2., If string contains Z remove Z
I wrote two regex already, but I can't combine them:
string.replace(/\T/g,' ') && string.replace(/\Z/g,'');
EDIT: I want the regex code to be shorter
Doesn't seem this even needs regex. Just 2 chained replacements would do.
var str = '[T] and [Z] but not [T] and [Z]';
var result = str.replace('T',' ').replace('Z','');
console.log(result);
However, a simple replace only replaces the first occurence.
To replace all, regex still comes in handy. By making use of the global g flag.
Note that the characters aren't escaped with \. There's no need.
var str = '[T] and [Z] and another [T] and [Z]';
var result = str.replace(/T/g,' ').replace(/Z/g,'');
console.log(result);
// By using regex we could also ignore lower/upper-case. (the i flag)
// Also, if more than 1 letter needs replacement, a character class [] makes it simple.
var str2 = '(t) or (Ⓣ) and (z) or (Ⓩ). But also uppercase (T) or (Z)';
var result2 = str2.replace(/[tⓉ]/gi,' ').replace(/[zⓏ]/gi,'');
console.log(result2);
But if the intention is to process really big strings, and performance matters?
Then I found out in another challenge that using an unnamed callback function inside 1 regex replace can prove to be faster. When compared to using 2 regex replaces.
Probably because if it's only 1 regex then it only has to process the huge string once.
Example snippet:
console.time('creating big string');
var bigstring = 'TZ-'.repeat(2000000);
console.timeEnd('creating big string');
console.log('bigstring length: '+bigstring.length);
console.time('double replace big string');
var result1 = bigstring.replace(/[t]/gi,'X').replace(/[z]/gi,'Y');
console.timeEnd('double replace big string');
console.time('single replace big string');
var result2 = bigstring.replace(/([t])|([z])/gi, function(m, c1, c2){
if(c1) return 'X'; // if capture group 1 has something
return 'Y';
});
console.timeEnd('single replace big string');
var smallstring = 'TZ-'.repeat(5000);
console.log('smallstring length: '+smallstring.length);
console.time('double replace small string');
var result3 = smallstring.replace(/T/g,'X').replace(/Z/g,'Y');
console.timeEnd('double replace small string');
console.time('single replace small string');
var result4 = smallstring.replace(/(T)|(Z)/g, function(m, c1, c2){
if(c1) return 'X';
return 'Y';
});
console.timeEnd('single replace small string');
Do you look for something like this?
ES6
var key = {
'T': ' ',
'Z': ''
}
"ATAZATA".replace(/[TZ]/g, (char) => key[char] || '');
Vanilla
"ATAZATA".replace(/[TZ]/g,function (char) {return key[char] || ''});
or
"ATAZATA".replace(/[TZ]/g,function (char) {return char==='T'?' ':''});
you can capture both and then decide what to do in the callback:
string.replace(/[TZ]/g,(m => m === 'T' ? '' : ' '));
var string = 'AZorro Tab'
var res = string.replace(/[TZ]/g,(m => m === 'T' ? '' : ' '));
console.log(res)
-- edit --
Using a dict substitution you can also do:
var string = 'AZorro Tab'
var dict = { T : '', Z : ' '}
var re = new RegExp(`[${ Object.keys(dict).join('') }]`,'g')
var res = string.replace(re,(m => dict[m] ) )
console.log(res)
Second Update
I have developed the following function to use in production, perhaps it can help someone else. It's basically a loop of the native's replaceAll Javascript function, it does not make use of regex:
function replaceMultiple(text, characters){
for (const [i, each] of characters.entries()) {
const previousChar = Object.keys(each);
const newChar = Object.values(each);
text = text.replaceAll(previousChar, newChar);
}
return text
}
Usage is very simple:
const text = '#Please send_an_information_pack_to_the_following_address:';
const characters = [
{
"#":""
},
{
"_":" "
},
]
const result = replaceMultiple(text, characters);
console.log(result); //'Please send an information pack to the following address:'
Update
You can now use replaceAll natively.
Outdated Answer
Here is another version using String Prototype. Enjoy!
String.prototype.replaceAll = function(obj) {
let finalString = '';
let word = this;
for (let each of word){
for (const o in obj){
const value = obj[o];
if (each == o){
each = value;
}
}
finalString += each;
}
return finalString;
};
'abc'.replaceAll({'a':'x', 'b':'y'}); //"xyc"
Related
Examples
dashed("Carpe Diem") ➞ "C-a-rp-e- D-i--e-m"
dashed("Fight for your right to party!") ➞ "F-i-ght f-o-r y-o--u-r r-i-ght t-o- p-a-rty!"
Notes
There are already a couple of solutions using regex; therefore, I am adding an answer which can be useful to someone who is not familiar with regex.
The following function, referenced by formatVowels, iterates the parameter string and uses String#indexOf to check if any of the characters is a vowel; if yes, it prepends and appends - to it and then adds the resulting text to the variable, result, otherwise, adds the character as it is to the variable, result.
const formatVowels = (str) => {
if (str == undefined) return "";
let result = "";
for (const ch of str) {
result += "AEIOU".indexOf(ch.toUpperCase()) != -1 ? "-" + ch + "-" : ch;
}
return result;
};
// Test
console.log(formatVowels('Hello'));
const my_replacer = (str)=> str.replace(/[aeiouAEIOU]/g,'-$&-')
let a = 'Carpe Diem'
console.log(my_replacer(a))
let b = 'Fight for your right to party!'
console.log(my_replacer(b))
coolString = `Cookke`;
function dashed(coolString) {
const regex = /a|e|i|o|u/gi;
console.log(coolString.replace(regex, `-$&-`));
}
dashed(coolString);
I'm working on a project on search about emoji and replace it with icon
but I have some problem on regular expression, Below mentioned is my code for reference:
var f = ["( :3 )" , "( :P )","\(:star:\)"];
var re = function(s){return new RegExp(s, 'g');};
now when I'm going to search about emoji and replace it as shown below:
s = "hello :D how are you :P dwdwd";
for(var n in f){
var m;
if ((m = re(f[n]).exec(s)) !== null) {
m.forEach((match, groupIndex) => {
s = s.replace(match,"<img src='http://abs.twimg.com/emoji/v1/72x72/"+ r[n] +".png'>");
});
}}
In this case, it works well and replace the emoji. But it only replace when there are space before and after emoji what should i do to replace the emoji in the begin of string or end !
s = ":D hello how are you :)";
This case is not working. How can i edit my regular expression for being able to replace emoji at begin and end of string and at the same time if its found in middle of string & have space between word and emoji
My 2nd problem with regular expression is "\(:star:\)" it never replaces. While it must replace word :star: with an emoji but i think i miss some thing on regular expression for it.
You can use beginning & ending anchors along with pipe to achieve this. For example:
/(^:3\s)|(\s:3\s)|(\s:3$)/g
^ is an anchor which matches :3\s to the beginning of the string.
$ is an anchor which matches \s:3 to the end of the string.
\s matches whitespace.
| is the pipe operator which acts as a logical OR operator between the different capture groups.
Just remove the spaces from your emoji regex.
var f = ["(:3)", "(:P)", "\(:star:\)"];
var r = ["[sadface]", "[toungeface]", "[staremoji]"];
var re = function(s) {
return new RegExp(s, 'g');
};
s = "hello :3 how are you :P dwdwd :star: :3";
console.log(s);
for (var n in f) {
var m;
if ((m = re(f[n]).exec(s)) !== null) {
m.forEach((match, groupIndex) => {
s = s.replace(match, r[n]);
});
}
}
console.log(s);
var content = "hello :D how are you :P dwdwd";
content = content.replace(/((:D|:P))/g,function(match){
var result = "";
var index = -1;
switch(match)
{
case ":D":
result = "happy";
index = 0
break;
case ":P":
result = "smilie";
index = 1
break;
}
if(index != -1)
{
return "<img src='http://abs.twimg.com/emoji/v1/72x72/"+index+".png'>";
}
return result;
});
console.log(content);
Please try this.
I created a more generic solution, starting with the mapping of emojis to the relevant names. Rather than two lists that need to be kept in synch, I used a single object:
const emojis = {
'(c)': 'a9',
'(r)': 'ae',
'(tm)': '2122'
//, ...
};
This strikes me as a much more useful structure to work with, but the code below could easily be altered to deal with the two-lists version.
Then I use a helper function to escape characters which are not allowed as plain text in Regular Expression by prepending them with \:
const escapeSpecials = (() => {
const specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'];
const reg = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
return str => str.replace(reg, '\\$1');
})();
Then I have the key function:
const replaceStringsWith = (emojis, convert) => str => Object.keys(emojis).reduce(
(str, em) => str.replace(new RegExp(`(^|\\s+)(${escapeSpecials(em)})($|\\s+)`, 'g'),
(m, a, b, c) => `${a}${convert(emojis[b], b)}${c}`),
str
);
This takes an object containing string/replacement pairs and a converter function which accepts the replacement and gives you back the final form. It returns a function which takes a string, and then searches for any matches on the keys of the object (properly checked for strings or string ends), replacing them with the result of calling the converter on the object's value for the particular key.
Thus we can do:
const toUrl = (name) => `<img src='http://abs.twimg.com/emoji/v1/72x72/${name}.png'>`;
const replaceEmojis = replaceStringsWith(emojis, toUrl)
and call it as
const s = "This is Copyright (c) 2017, FooBar is (tm) BazCo (r)";
replaceEmojis(s); //=>
// `This is Copyright <img src='http://abs.twimg.com/emoji/v1/72x72/a9.png'>
// 2017, FooBar is <img src='http://abs.twimg.com/emoji/v1/72x72/2122.png'>
// BazCo <img src='http://abs.twimg.com/emoji/v1/72x72/ae.png'>`
Note that the converter also takes a second parameter. So you could instead use
const toUrl = (name, emoji) =>
`<img src='http://abs.twimg.com/emoji/v1/72x72/${name}.png' title='${emoji}'>`;
to get
//=> `This is Copyright <img
// src='http://abs.twimg.com/emoji/v1/72x72/a9.png' title='(c)'>
// 2017, FooBar is <img src='http://abs.twimg.com/emoji/v1/72x72/2122.png'
// title='(tm)'> BazCo <img src='http://abs.twimg.com/emoji/v1/72x72/ae.png' title='(r)'>"
I'm aware of the CSS attribute text-transform: capitalize but can anyone help me with replicating this using Javascript?
I would like to pass an argument to my function which will return the string with the first letter of each word capitalized.
I've got this far but I'm stuck trying to break my array of strings in to chunks:
function upper(x){
x = x.split(" ");
// this function should return chunks but when called I'm getting undefined
Array.prototype.chunk = function ( n ) {
return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
};
x = x.chunk;
}
upper("chimpanzees like cigars")
after the chunk I'm guessing I need to again split each chunk in to the first character and the remaining characters, use .toUpperCase() on the first character, join it back up with the remaining and then join up the chunks again in to a string?
Is there a simpler method for doing this?
I came up with a solution for both a single word and also for an array of words. It will also ensure that all other letters are lowercase for good measure. I used the Airbnb style guide as well. I hope this helps!
const mixedArr = ['foo', 'bAr', 'Bas', 'toTESmaGoaTs'];
const word = 'taMpa';
function capitalizeOne(str) {
return str.charAt(0).toUpperCase().concat(str.slice(1).toLowerCase());
}
function capitalizeMany(args) {
return args.map(e => {
return e.charAt(0).toUpperCase().concat(e.slice(1).toLowerCase());
});
};
const cappedSingle = capitalizeOne(word);
const cappedMany = capitalizeMany(mixedArr);
console.log(cappedSingle);
console.log(cappedMany);
The map function is perfect for this.
w[0].toUpperCase() : Use this to capitalize the first letter of each word
w.slice(1): Return the string from the second character on
EDGE Case
If the user doesn't enter a string, the map function will not work and an error will be raised. This can be guarded against by checking if the user actually entered something.
var userInput = prompt("Enter a string");
var capitalizedString = userInput == "" ? "Invalid String" :
userInput.split(/\s+/).map(w => w[0].toUpperCase() + w.slice(1)).join(' ');
console.log(capitalizedString);
You can use the following solution which doesn't use regex.
function capitalize(str=''){
return str.trim().split('')
.map((char,i) => i === 0 ? char.toUpperCase() : char )
.reduce((final,char)=> final += char, '' )
}
capitalize(' hello') // Hello
"abcd efg ijk lmn".replace(/\b(.)/g, (m => m.toUpperCase())) // Abcd Efg Ijk Lmn
You may want to try a regex approach:
function upperCaseFirst(value) {
var regex = /(\b[a-z](?!\s))/g;
return value ? value.replace(regex, function (v) {
return v.toUpperCase();
}) : '';
}
This will grab the first letter of every word on a sentence and capitalize it, but if you only want the first letter of the sentence, you can just remove the g modifier at the end of the regex declaration.
or you could just iterate the string and do the job:
function capitalize(lowerStr){
var result = "";
var isSpacePrevious = false;
for (var i=0; i<lowerStr.length; i++){
if (i== 0 || isSpacePrevious){
result += lowerStr[i].toUpperCase();
isSpacePrevious = false;
continue;
}
if (lowerStr[i] === ' '){
isSpacePrevious = true;
}
result += lowerStr[i];
}
return result;
}
I have a string which is composed of terms separated by slashes ('/'), for example:
ab/c/def
I want to find all the prefixes of this string up to an occurrence of a slash or end of string, i.e. for the above example I expect to get:
ab
ab/c
ab/c/def
I've tried a regex like this: /^(.*)[\/$]/, but it returns a single match - ab/c/ with the parenthesized result ab/c, accordingly.
EDIT :
I know this can be done quite easily using split, I am looking specifically for a solution using RegExp.
NO, you can't do that with a pure regex.
Why? Because you need substrings starting at one and the same location in the string, while regex matches non-overlapping chunks of text and then advances its index to search for another match.
OK, what about capturing groups? They are only helpful if you know how many /-separated chunks you have in the input string. You could then use
var s = 'ab/c/def'; // There are exact 3 parts
console.log(/^(([^\/]+)\/[^\/]+)\/[^\/]+$/.exec(s));
// => [ "ab/c/def", "ab/c", "ab" ]
However, it is unlikely you know that many details about your input string.
You may use the following code rather than a regex:
var s = 'ab/c/def';
var chunks = s.split('/');
var res = [];
for(var i=0;i<chunks.length;i++) {
res.length > 0 ? res.push(chunks.slice(0,i).join('/')+'/'+chunks[i]) : res.push(chunks[i]);
}
console.log(res);
First, you can split the string with /. Then, iterate through the elements and build the res array.
I do not think a regular expression is what you are after. A simple split and loop over the array can give you the result.
var str = "ab/c/def";
var result = str.split("/").reduce(function(a,s,i){
var last = a[i-1] ? a[i-1] + "/" : "";
a.push(last + s);
return a;
}, []);
console.log(result);
or another way
var str = "ab/c/def",
result = [],
parts=str.split("/");
while(parts.length){
console.log(parts);
result.unshift(parts.join("/"));
parts.pop();
}
console.log(result);
Plenty of other ways to do it.
You can't do it with a RegEx in javascript but you can split parts and join them respectively together:
var array = "ab/c/def".split('/'), newArray = [], key = 0;
while (value = array[key++]) {
newArray.push(key == 1 ? value : newArray[newArray.length - 1] + "/" + value)
}
console.log(newArray);
May be like this
var str = "ab/c/def",
result = str.match(/.+?(?=\/|$)/g)
.map((e,i,a) => a[i-1] ? a[i] = a[i-1] + e : e);
console.log(result);
Couldn't you just split the string on the separator character?
var result = 'ab/c/def'.split(/\//g);
What is the best way to bold a part of string in Javascript?
I have an array of objects. Each object has a name. There is also an input parameter.
If, for example, you write "sa" in input, it automatically searches in array looking for objects with names that contain "sa" string.
When I print all the names, I want to bold the part of the name that coincide with the input text.
For example, if I search for "Ma":
Maria
Amaria
etc...
I need a solution that doesn't use jQuery. Help is appreciated.
PD: The final strings are in the tag. I create a list using angular ng-repeat.
This is the code:
$scope.users = data;
for (var i = data.length - 1; i >= 0; i--) {
data[i].name=data[i].name.replace($scope.modelCiudad,"<b>"+$scope.modelCiudad+"</b>");
};
ModelCiudad is the input text content var. And data is the array of objects.
In this code if for example ModelCiudad is "ma" the result of each is:
<b>Ma</b>ria
not Maria
You can use Javascript's str.replace() method, where str is equal to all of the text you want to search through.
var str = "Hello";
var substr = "el";
str.replace(substr, '<b>' + substr + '</b>');
The above will only replace the first instance of substr. If you want to handle replacing multiple substrings within a string, you have to use a regular expression with the g modifier.
function boldString(str, substr) {
var strRegExp = new RegExp(substr, 'g');
return str.replace(strRegExp, '<b>'+substr+'</b>');
}
In practice calling boldString would looks something like:
boldString("Hello, can you help me?", "el");
// Returns: H<b>el</b>lo can you h<b>el</b>p me?
Which when rendered by the browser will look something like: Hello can you help me?
Here is a JSFiddle with an example: https://jsfiddle.net/1rennp8r/3/
A concise ES6 solution could look something like this:
const boldString = (str, substr) => str.replace(RegExp(substr, 'g'), `<b>${substr}</b>`);
Where str is the string you want to modify, and substr is the substring to bold.
ES12 introduces a new string method str.replaceAll() which obviates the need for regex if replacing all occurrences at once. It's usage in this case would look something like this:
const boldString = (str, substr) => str.replaceAll(substr, `<b>${substr}</b>`);
I should mention that in order for these latter approaches to work, your environment must support ES6/ES12 (or use a tool like Babel to transpile).
Another important note is that all of these approaches are case sensitive.
Here's a pure JS solution that preserves the original case (ignoring the case of the query thus):
const boldQuery = (str, query) => {
const n = str.toUpperCase();
const q = query.toUpperCase();
const x = n.indexOf(q);
if (!q || x === -1) {
return str; // bail early
}
const l = q.length;
return str.substr(0, x) + '<b>' + str.substr(x, l) + '</b>' + str.substr(x + l);
}
Test:
boldQuery('Maria', 'mar'); // "<b>Mar</b>ia"
boldQuery('Almaria', 'Mar'); // "Al<b>mar</b>ia"
I ran into a similar problem today - except I wanted to match whole words and not substrings. so if const text = 'The quick brown foxes jumped' and const word = 'foxes' than I want the result to be 'The quick brown <strong>foxes</strong> jumped'; however if const word = 'fox', than I expect no change.
I ended up doing something similar to the following:
const pattern = `(\\s|\\b)(${word})(\\s|\\b)`;
const regexp = new RegExp(pattern, 'ig'); // ignore case (optional) and match all
const replaceMask = `$1<strong>$2</strong>$3`;
return text.replace(regexp, replaceMask);
First I get the exact word which is either before/after some whitespace or a word boundary, and then I replace it with the same whitespace (if any) and word, except the word is wrapped in a <strong> tag.
Here is a version I came up with if you want to style words or individual characters at their index in react/javascript.
replaceAt( yourArrayOfIndexes, yourString/orArrayOfStrings )
Working example: https://codesandbox.io/s/ov7zxp9mjq
function replaceAt(indexArray, [...string]) {
const replaceValue = i => string[i] = <b>{string[i]}</b>;
indexArray.forEach(replaceValue);
return string;
}
And here is another alternate method
function replaceAt(indexArray, [...string]) {
const startTag = '<b>';
const endTag = '</b>';
const tagLetter = i => string.splice(i, 1, startTag + string[i] + endTag);
indexArray.forEach(tagLetter);
return string.join('');
}
And another...
function replaceAt(indexArray, [...string]) {
for (let i = 0; i < indexArray.length; i++) {
string = Object.assign(string, {
[indexArray[i]]: <b>{string[indexArray[i]]}</b>
});
}
return string;
}
Above solutions are great, but are limited! Imagine a test scenerio where you want to match case insensitive query in a string and they could be multiple matches.
For example
Query: ma
String: The Amazing Spiderman
Expected Result: The Amazing Spiderman
For above scenerio, use this:
const boldMatchText = (text,searchInput) => {
let str = text.toLowerCase();
const query = searchInput.toLowerCase();
let result = "";
let queryLoc = str.indexOf(query);
if (queryLoc === -1) {
result += text;
} else
do {
result += ` ${text.substr(0, queryLoc)}
<b>${text.substr(queryLoc, query.length)}</b>`;
str = str.substr(queryLoc + query.length, str.length);
text = text.substr(queryLoc + query.length, str.length);
queryLoc = str.indexOf(query);
} while (text.length > 0 && queryLoc !== -1);
return result + text;
};