I need a function in JavaScript that takes one string as input, replaces many substrings with their corresponding values, then returns the result. For example:
function findreplace(inputStr) {
const values = {"a": "A",
"B": "x",
"c": "C"};
// In this example, if inputStr is "abc", then outputStr should be "AbC".
return outputStr
}
I know how to individually find and replace, but I was wondering if there was an easy way to do this with many pairs of (case-sensitive) values at once.
Thank you!
Just iterate over values with the help of Object.entries(values):
function findreplace(inputStr) {
const values = {
"a": "A",
"B": "x",
"c": "C"
};
for (const [search, replace] of Object.entries(values)) {
inputStr = inputStr.replace(search, replace);
}
return inputStr;
}
console.log(findreplace("abc"));
You can join keys to build a regex and then replace accordingly
function findreplace(inputStr) {
let values = { "a": "A", "B": "x", "c": "C" };
let regex = new RegExp("\\b" + Object.keys(values).join('|') + "\\b", 'g')
return inputStr.replace(regex, (m) => values[m] )
}
console.log(findreplace('aBc'))
console.log(findreplace('AbC'))
console.log(findreplace('ABC'))
Related
So here's an example:
{
"part": "Intro",
"e": "------5/6------8\\6-|-------------------|-------------------",
"B": "-----------9-------|---------6p8---(6)-|-------------------",
"G": "--8----------------|---8h9-------------|--<8>--------------",
"D": "",
"A": "",
"E": "",
"endMsg": "Continue..."
}
Note: The double-slash will turn into one slash only upon render of text.
I want to get value from this object that is not empty. (So that could be from the e key or from the B key. As long it's not empty.)
Then I'm replacing that value using this expression here:
str.replace(/[0-9-. a-zA-Z // \ ~ ( ) < >]/g, '-');
It's for replacing the numbers, letters, and other characters into dashes.
I want to use that value with the dashes and pipe chars only to fill up the other keys inside the same object that are empty.
In the end, I want it to look something like this:
{
"part": "Intro",
"e": "------5/6------8\\6-|-------------------|-------------------",
"B": "-----------9-------|---------6p8---(6)-|-------------------",
"G": "--8----------------|---8h9-------------|--<8>--------------",
"D": "-------------------|-------------------|-------------------",
"A": "-------------------|-------------------|-------------------",
"E": "-------------------|-------------------|-------------------",
"endMsg": "Continue..."
}
I have no idea how to achieve this in code. Please help.
You can loop over each key value pair and replace the value if its empty. Be aware that a backslash is used for escaping a character. To fix this we first replace the backslashes with dashes and then replace the rest.
The regex could also be simplified to /[^-|]/g which means replace all symbols except - and |
const lines = {
"part": "Intro",
"e": "------5/6-----8\\6-|-------------------|-------------------",
"B": "-----------9-------|---------6p8---(6)-|-------------------",
"G": "--8----------------|---8h9-------------|--<8>--------------",
"D": "",
"A": "",
"E": "",
"endMsg": "Continue..."
};
const createFullLines = (lines, blacklist = ['part', 'endMsg']) => {
// Find a line that is not empty
const line = Object.entries(lines).find(([key, line]) => {
return !blacklist.includes(key) && line.trim();
});
// Exit if all lines are empty
if(!line) return lines;
// Destructure to get only value
const [_, filledLine] = line;
// Create new line with only dashes
const newLine = filledLine.replace(/[^-|]/g, '-');
// Update lines
for(const key in lines) {
lines[key] ||= newLine;
}
return lines;
}
const result = createFullLines(lines);
console.log(result);
You should just iterate between your object's keys like this:
// find first non-empty field, !! - conversion to boolean
let nonEmptyKey = Object.keys(obj).find(key => !!obj[key]);
for(let key of Object.keys(obj)) {
// check if value is empty
if(!obj[key]) {
obj[key] = obj[nonEmptyKey].replace(/[0-9-. a-zA-Z // \ ~ ( ) < >]/g, '-');
}
}
Also, you can simplify your regex to this:
// replace all symbols except - and |
str.replace(/[^-|]/g, '-');
I understand that regex is a possibility, but I'd like to edit a lot of things at once. Minimalizing chaining. It just doesn't look to great in code.
for example,
Let's say the alphabet is jumbled up.
A would be E
B would be H
E would be D
How would I change ABE into EHD using a minimal amount of functions?
To be crystal clear, I have an object with this jumbled up alphabet.
TL;DR:
Best way to bulk-update letters in a string to their assigned counterparts?
You could write some logic where you would split the string into an array of characters and then compare the separate values using map() and replace when needed. Then join the array back to a string.
const original = "ABE";
const splitted = original.split("");
const replaced = splitted.map((letter) => {
if(letter === "A") return "E"
if(letter === "B") return "H"
if(letter === "E") return "D"
return letter
});
console.log(replaced.join(""));
The easiest would be to use a regular expression but also pair it with a replacer function:
const substitutions = {
"A": "E",
"B": "H",
"E": "D"
};
function transform(input) {
return input.replace(/./g, char => {
const sub = substitutions[char] ?? char;
return sub;
});
}
console.log(transform("HELLO WORLD!"));
console.log(transform("BEAUTIFUL!"));
console.log(transform("BOATS ARE EXCELLENT 👍"));
The regex /./g simply matches every single character and the replacer function then checks if it exists in substitutions and returns that. Or if it doesn't exist, it falls back to the same character thanks to the nullish coalescing operator (??).
This requires you to specify lowercase and uppercase characters explicitly in substitutions.
const substitutions = {
"a": "e",
"A": "E",
"b": "h",
"B": "H",
"e": "d",
"E": "D"
};
function transform(input) {
return input.replace(/./g, char => {
const sub = substitutions[char] ?? char;
return sub;
});
}
console.log(transform("Hello world!"));
console.log(transform("Beautiful!"));
console.log(transform("Boats Are Excellent 👍"));
If you always want the replacement to match the case (a -> e and A -> E) and do not want the extra entries in substitutions, then you can can check the case of the character and transform the replacement:
const substitutions = {
"A": "E",
"B": "H",
"E": "D"
};
function transform(input) {
return input.replace(/./g, char => {
const upperChar = char.toLocaleUpperCase();
if (!(upperChar in substitutions))
return char;
const isUpper = char === upperChar;
const sub = substitutions[upperChar];
if (isUpper)
return sub.toLocaleUpperCase();
return sub.toLocaleLowerCase();
});
}
console.log(transform("Hello world!"));
console.log(transform("Beautiful!"));
console.log(transform("Boats Are Excellent 👍"));
I want to replace each letter in more one word like this example:
if user typed #(*#$^ $^* by the code I want to change each letter to cinema man. Explaining more - I want to make a map like this:
"#" = "c";
"(" = "i";
"*" = "n";
"#" = "e";
"$" = "m";
"^" = "a";
How I can make that process with JavaScript?
If you're just wanting to map those specific characters, you can do something like this:
var myMap = {
"#": "c",
"(": "i",
"*": "n"
};
var string = "#(*";
var newLetters = string.split('').map(function(letter){
return myMap[letter];
});
newLetters.join('');
You just need to create an object to reference it's key-value pair.
Edit: Obviously you can fix this to work to your liking, just something I whipped up to illustrate the over all idea.
Create a object in order to store the mapping. Now parse the string and replace each word with its mapped work. Here is a working demo:
var mapping = {
"#": "c",
"(": "i",
"*": "n",
"#": "e",
"$": "m",
"^": "a"
};
var string = "#(*#$^ $^*";
var output = string.split("").map(function(el) {
if(mapping.hasOwnProperty(el))
return mapping[el];
return el;
}).join("");
alert(output);
This might be a simple question but, how do i split words... for example
a = "even, test"
I have used .split to seperate the text with space.
so the result came is like
a = "even,"
b = "test"
But, how do I remove the 'comma' here?
But in some conditions it might get "even test" and in some conditions i might get "even, test". All are dynamic, so how do i check it for both?
Thanks
Firstly, the split() function is not jQuery - it is pure Javascript.
Did you try doing split with a comma and a space? That would have worked just fine in your case:
var result = input.split(', ');
For more complex splits, you can use regular expression pattern matching to allow multiple commas or spaces between the two fields:
var result = input.split(/[, ]+/);
but you probably don't need to go that far in your case.
I think is better to use something like this:
text.match(/[a-z'\-]+/gi);
Example:
var e=function()
{
var r=document.getElementById('r');
var x=document.getElementById('t').value.match(/[a-z'\-]+/gi);
for(var i=0;i<x.length;i++)
{
var li=document.createElement('li');
li.innerText=x[i];
r.appendChild(li);
}
}
<div style="float:right;width:18%">
<ol id="r" style="display:block;width:auto;border:1px inner;overflow:scroll;height:8em;max-height:10em;"></ol>
<button onclick="e()">Extract words!</button>
</div>
<textarea id="t" style="width:70%;height:12em">even, test; spider-man
But saying o'er what I have said before:
My child is yet a stranger in the world;
She hath not seen the change of fourteen years,
Let two more summers wither in their pride,
Ere we may think her ripe to be a bride.
—Shakespeare, William. The Tragedy of Romeo and Juliet</textarea>
I found a list of word separators in Sublime Text default settings.
Here's how to split with it, with some Unicode support (the defined separators are not Unicode though):
{ // word_separators: ./\()"'-,;<>~!##$%^&*|+=[]{}`~?: (32)
function splitByWords(str = '', limit = undefined) {
return str.split(/[-./\\()"',;<>~!##$%^&*|+=[\]{}`~?:]/u, limit)
}
function reverseString(str) {
let newString = ''
for (let i = str.length - 1; i >= 0; i--)
newString += str[i]
return newString
}
const str = '123.x/x\\x(x)x"x\'x-x:x,789;x<x>x~x!x#x#x$x%x^x&x*x|x+x=x[x]x{x}x`x~x?456'
console.log(splitByWords(str)) // (33) ["123", "x", "x", "x", "x", "x", "x", "x", "x", "x", "789", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "456"]
console.log(splitByWords(str, 1)) // ["123"]
console.log(splitByWords(reverseString(str), 1)) // ["654"]
}
For some reason the - has to be at the beginning, and the : at the end.
Edit: you might want to add \s (after the -) to count whitespace as separator
Just use this code:
var a = "even, test";
var words = a.split(", ");
a.split(',')
or
var re = /\s*,\s*/
var newA = a.split(re);
I think you could do it like this:
var a= 'even,'
var newA = a.slice(0, -1)
This will remove the last char from a given string.
And to check if the string contains a comma, I would do the following:
if (a.indexOf(",") >= 0){
//contains a comma
} else {
//no comma
}
I am a javascript beginner, so this probably is not the best way to do it, but nevertheless it works.
Hej Harry
if the comma is the separator you can call split with the comma
Ex:
var newColls = myString.split(",");
and not split with space.
GL
I have been trying to use a simple jQuery operation to dynamically match and store all anchor tags and their texts on the page. But I have found a weird behavior. When you are using match() or exec(), if you designate the needle as a separate RegExp object or a pattern variable, then your query matches only one instance among dozens in the haystack.
And if you designate the pattern like this
match(/needle/gi)
then it matches every instance of the needle.
Here is my code.
You can even fire up Firebug and try this code right here on this page.
var a = {'text':'','parent':[]};
$("a").each(function(i,n) {
var module = $.trim($(n).text());
a.text += module.toLowerCase() + ',' + i + ',';
a.parent.push($(n).parent().parent());
});
var stringLowerCase = 'b';
var regex = new RegExp(stringLowerCase, "gi");
//console.log(a.text);
console.log("regex 1: ", regex.exec(a.text));
var regex2 = "/" + stringLowerCase + "/";
console.log("regex 2: ", a.text.match(regex2));
console.log("regex 3: ", a.text.match(/b/gi));
For me it is returning:
regex 1: ["b"]
regex 2: null
regex 3: ["b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b"]
Can anyone explain the root of this behavior?
EDIT: I forgot to mention that for regex1, it doesn't make any difference whether you add the flags "gi" for global and case insensitive matching. It still returns only one match.
EDIT2: SOlved my own problem. I still don't know why one regex1 matches only one instance, but I managed to match all instances using the match() and the regex1.
So..this matches all and dynamically!
var regex = new RegExp(stringLowerCase, "gi");
console.log("regex 2: ", a.text.match(regex));
This is not unusual behaviour at all. In regex 1 you are only checking for 1 instance of it where in regex 3 you have told it to return all instances of the item by using the /gi argument.
In Regex 2 you are assuming that "/b/" === /b/ when it doesn't. "/b/" !== /b/. "/b/" is a string that is searching so if you string has "/b/" in it then it will return while /b/ means that it needs to search between the slashes so you could have "abc" and it will return "b"
I hope that helps.
EDIT:
Looking into it a little bit more, the exec methods returns the first match that it finds rather than all the matches that it finds.
EDIT:
var myRe = /ab*/g;
var str = "abbcdefabh";
var myArray;
while ((myArray = myRe.exec(str)) != null)
{
var msg = "Found " + myArray[0] + ". ";
msg += "Next match starts at " + myRe.lastIndex;
console.log(msg);
}
Having a look at it again it definitely does return the first instance that it finds. If you looped through it then would return more.
Why it does this? I have no idea...my JavaScript Kung Fu clearly isnt strong enough to answer that part
The reason regex 2 is returning null is that you're passing "/b/" as the pattern parameter, while "b" is actually the only thing that is actually part of the pattern. The slashes are shorthand for regex, just as [ ] is for array. So if you were to replace that to just new regex("b"), you'd get one match, but only one, since you're omitting the "global+ignorecase" flags in that example. To get the same results for #2 and #3, modify accordingly:
var regex2 = stringLowerCase;
console.log("regex 2: ", a.text.match(regex2, "gi"));
console.log("regex 3: ", a.text.match(/b/gi));
regex2 is a string, not a RegExp, I had trouble too using this kind of syntax, tho i'm not really sure of the behavior.
Edit : Remebered : for regex2, JS looks for "/b/" as a needle, not "b".