Related
I need to replace two strings using regular expression value replacement so the resulting string is $?tlang=es&text=Hello world, so I didn't know to use here String.prototype.replace().
const value = "Hello world"
const queryString = "?tlang=es&text=$1"
In this scenary, value and queryString are hard-coded, but in "real life" it should be the result of a regular expression group capturing like line.match(/msgid \"(.*)\"/) where line is an iterated text line and queryString is what the user submitted.
I thought I just could do this, but maybe it's too much effort where there is a better solution (that I couldn't find):
const line = "Full name: John Doe" // text input
const sourcePattern = /Full name: (.*) (.*)/ // user input
let queryString = 'name=$1&lname=$2' // user input
const matches = line.match(sourcePattern)
matches.splice(0, 1)
for (let i = 0; i < matches.length; i++) {
queryString = queryString.replace(`\$${i+1}`, matches[i])
}
Any ideas?
Regular expressions are fine to extract the values from the first string. But for working with query strings there's a built in class that helps:
const entries = [...new URLSearchParams(queryString).entries()]
if (matches.length !== entries.length) {
// handle error
}
const replaced = entries.reduce((params, [key], index) => {
params.append(key, matches[index]);
return params;
}, new URLSearchParams());
You can call toString() on it to get the modified query string. Generally speaking you want to avoid doing string processing any time there's a readily available richer data type.
You could compact the code a little as follows:
const line = "Full name: John Doe" // text input
const sourcePattern = /Full name: (.*) (.*)/ // user input
let queryString = 'name=$1&lname=$2' // user input
const [_, ...matches] = line.match(sourcePattern)
console.log(queryString.split(/\$\d+/)
.map((p,i)=>`${p}${matches[i]??''}`).join(''))
var string = "Please click on dashboard and then open the dashboard details to verify your details on the data";
var stringArray = ["dashboard" , "dashboard" , "data"]
var replaceArray = ["https://abcd.com/login" , "https://abcd.com/home" , "https://abcd.com/data"]
for(i=0;i<stringArray.length; i++){
string = string.replace(stringArray[i].trim(), "<a href='"+replaceArray[i].trim()+"'>"+stringArray[i].trim()+"</a>");
}
I have a string and 2 arrays like above. I need to replace my string with respective anchor link tags as mentioned in two arrays. stringArray defines the word to be linked and replaceArray defines the URL should be added. Like first occurrence of dashboard should be anchor linked with "https://abcd.com/login" and second occurance of "dashboard" should be replaced with "https://abcd.com/home" and "data" should be replaced with "https://abcd.com/data".
I tried to find out the word in string and replace it using replace/replaceAll, working fine for single occurrence word, but for multiple occurrences it is not working.
Anyone help me to resolve this.
Resulting :
"Please click on <a href='https://abcd.com/login'><a href='https://abcd.com/home'>dashboard</a></a> and then open the dashboard details to verify your details on the <a href='https://abcd.com/data'>data</a>"
Expected Output:
"Please click on <a href='https://abcd.com/login'>dashboard</a> and then open the <a href='https://abcd.com/home'>dashboard</a> details to verify your details on the <a href='https://abcd.com/data'>data</a>"
When using a string as the first parameter (substring) to the Javascript replace function, replace will find and replace only the first occurrence of the substring. That's why both your "login" and "home" links are nested around the first occurrence of "dashboard", and the remaining occurrences of "dashboard" remain unchanged. Using a regular expression as the first parameter is one solution, however not the only solution...
Using indexOf() to keep track of the last index where word from array strArray was matched, then slice-ing the string after the last insertion to continue the replacement search from there:
var string = "Please click on dashboard and then open the dashboard details to verify your details on the data";
var stringArray = ["dashboard", "dashboard", "data"]
var replaceArray = ["https://abcd.com/login", "https://abcd.com/home", "https://abcd.com/data"]
// keep track of last position of matched string
let ii = 0;
for (i = 0; i < stringArray.length; i++) {
let str = stringArray[i].trim();
let repstr = '' + str + '';
// move position to index of matched string
ii += string.slice(ii).indexOf(str);
string =
// this is the portion of string before and including last replacement
string.slice(0, ii)
// this is the portion after last replacement
+ string.slice(ii).replace(str, repstr);
// move position to past current replacement
ii += repstr.length;
}
console.log(string);
// Please click on dashboard and then open the dashboard details to verify your details on the data
And this solution benchmarks about 120 times faster than both the regular expression solution, and the reduce solutions I posted below.
Here's a solution combining the words and links into a single array, then using reduce to iterate the array replace_arr, update the string string, and maintain the match index ii:
let string = "Please click on dashboard and then open the dashboard details to verify your details on the data";
const replace_arr = [["dashboard", "https://abcd.com/login"], ["dashboard", "https://abcd.com/home"], ["data", "https://abcd.com/data"]];
replace_arr.reduce(
(ii, [str, link]) => {
let repstr = '' + str + '';
ii += string.slice(ii).indexOf(str);
string = string.slice(0, ii)
+ string.slice(ii).replace(str, repstr)
return ii + repstr.length;
}
, 0
);
console.log(string);
// Please click on dashboard and then open the dashboard details to verify your details on the data
Refactored reduction method for better performance—initially including string in the reduce() function, and processing internally, cuts execution time almost in half, compared to accessing the string externally to the reduction process with each iteration:
let string = "Please click on dashboard and then open the dashboard details to verify your details on the data";
const replace_arr = [["dashboard", "https://abcd.com/login"], ["dashboard", "https://abcd.com/home"], ["data", "https://abcd.com/data"]];
[string] = replace_arr.reduce(([ss, ii], [str, link]) => {
let repstr = '' + str + '';
ii += ss.slice(ii).indexOf(str);
return [ss.slice(0, ii) +
ss.slice(ii).replace(str, repstr), ii + repstr.length
];
}, [string, 0]);
console.log(string);
// Please click on dashboard and then open the dashboard details to verify your details on the data
...and this final solution benchmarks nearly twice as fast as the regex solution. :)
Here a solution using a regex with lookaround:
const text = "Please click on dashboard and then open the dashboard details to verify your details on the data or the other data";
const tokens = ["dashboard", "dashboard", "data", "data"]
const links = ["https://abcd.com/login", "https://abcd.com/home", "https://abcd.com/data", "https://abcd.com/dashboard/data"]
var result = text;
for (i = 0; i < tokens.length; i++) {
const re = new RegExp('(?<=.*)((?<= )' + tokens[i] + '(?= |$))(?=.*)');
result = result.replace(re, '$&'); //TODO array length validation
}
console.log(result)
This regex will only work for tokens surrounded by whitespaces to avoid replacing the texts inside URLs.
You can see more about lookahead and lookbehind here and about browser compatibility here.
How about this one guy,
var string = "Please click on dashboard and then open the dashboard details to verify your details on the data";
const stringArray = string.split(' ');
var targetTexts = ["dashboard" , "dashboard" , "data"]
var replaceTexts = ["https://abcd.com/login" , "https://abcd.com/home" , "https://abcd.com/data"]
const resultArray = []
for (let i = 0; i < stringArray.length; i++) {
const word = stringArray[i];
const targetTextIndex = targetTexts.indexOf(word);
if (targetTextIndex > -1) {
resultArray.push("<a href='"+replaceTexts[targetTextIndex]+"'>"+word+"</a>")
targetTexts = targetTexts.filter((_el, idx) => idx !== targetTextIndex)
replaceTexts = replaceTexts.filter((_el, idx) => idx !== targetTextIndex)
} else {
resultArray.push(word);
}
}
console.log(resultArray.join(' '))
I hope you get a hint on this one.
It works like a charm, there will be exception handling for you to handle.
The presented approach consists of
a mapping task which firstly merges two related arrays, the list of search terms and the list of hypertext references, into another array of replacement items.
a reduce tasks which processes a list of replacement items and safely (without running into the same but already replaced search again) replaces each search by its related complete hypertext expression.
The 2nd part gets achieved by making use of the offset parameter of the replace method's replacerFunction. Upon the offset value, the current matches index, one can programmatically (while reducing) split the originally provided string value into processed and unprocessed substrings/partials. The reduce task's array result gets joined back into the final entirely replaced string value.
function createReplacementItemFromBoundHrefs(search, idx) {
const hrefList = this;
return {
search,
href: hrefList[idx],
}
}
function aggregateSafelyReplacedHrefPartials(partials, { search, href }) {
// intentionally mutates `partials`, an array of zero to many
// processed substrings and always an unprocessed (last item)
// `target` substring of the originally provided string value.
const target = partials.pop();
let sliceAt;
const result = target
.replace(
// a case insensitive search regex.
RegExp(`${ search }`, 'i'),
// a replacer function which helps preventing multiple
// manipulations of always the same search/replace term.
(match, offset) => {
const replacement = `${ match }`;
sliceAt = offset + replacement.length;
return replacement;
},
);
return [
...partials, // - processed lately.
result.slice(0, sliceAt), // - processed latest.
result.slice(sliceAt), // - to be processed.
];
}
function safelyReplaceSearchWithRelatedHref(str, searchList, hrefList) {
return searchList
.map(createReplacementItemFromBoundHrefs, hrefList)
.reduce(aggregateSafelyReplacedHrefPartials, [str])
.join('');
}
const string = "Please click on dashboard and then open the dashboard details to verify your details on the data";
const stringArray = [
"dashboard",
"dashboard",
"data",
];
const replaceArray = [
"https://abcd.com/login",
"https://abcd.com/home",
"https://abcd.com/data",
];
console.log(
'before ... ',
string,
'\n\nafter ... ',
safelyReplaceSearchWithRelatedHref(string, stringArray, replaceArray),
);
console.log(
stringArray
.map(createReplacementItemFromBoundHrefs, replaceArray)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
"I have another use case, with an occurrences array , i only want to replace that specific occurrence word from the string. From below, 1 and 3 occurrences of dashboard and 2nd occurrence of data should be replaced. Can you help me with this.. ?? [...] var string = 'On dashboard, then open dashboard details, verify your dashboard details on data and other data'; var wordsArray = ['dashboard', 'dashboard', 'data']; var occurrences = [1 , 3 , 2]; var linksArray = ['abcd.com/login', 'abcd.com/home', 'abcd.com/data'];" – Siva_K22
For this the above presented first solution could be easily refactored into a new one which keeps the two folded approach.
The first task would be the creation of a replacement tracker which enables a replacer function to keep track of each search's current occurrence count and replacement.
The second task straightforwardly does replace the provided original string via
a case insensitive regex which features any possible word/search ... and ...
a replacer function which keeps track of each search's occurrence and upon a search's current occurrence count decides whether to really replace a search by its related full hypertext reference or just with itself (its very own match).
"#PeterSeliger -- Yea, but i resolved that with below RegEx.. string= string.replace(new RegExp("(?:(?:.|\n)*?"+currentstring+"){"+occurence+"}"), function(x){return x.replace(RegExp(currentstring+"$"), replaceString)});" – Siva_K22
Again a regex only approach will never be as reliable (also not as readable) as one that truly tracks search occurrences and was implemented with both goals being generic on one hand but also specialized enough (a regex only approach is limited much earlier in the latter terms).
function aggregateReplacementTrackerFromBoundData(collector, search, idx) {
const { occurrences = [], hrefList = [], tracker = {} } = collector;
// create and/or access and aggregate
// a search specific occurrence tracker.
(tracker[search.toLowerCase()] ??= {
occurrence: {},
occurrenceCount: 0,
})
.occurrence[ occurrences[idx] ] = hrefList[idx];
return { occurrences, hrefList, tracker };
}
function safelyReplaceSearchOccurrencesWithRelatedHref(
str, searchList, hrefList, occurrences,
) {
// create an overall replacement tracker for any search.
const { tracker } = searchList
.reduce(aggregateReplacementTrackerFromBoundData, {
occurrences,
hrefList,
tracker: {},
});
return str
.replace(
// a case insensitive regex which features any possible word/search.
RegExp(`\\b(?:${ searchList.join('|') })\\b`, 'gi'),
// a replacer function which keeps track of each search's occurrence
// and upon a search's current occurrence count decides whether to
// really replace a search by its related full hypertext reference
// or just with itself (its very own match).
(match/*, offset, target*/) => {
const searchTracker = tracker[match.toLowerCase()];
const count = ++searchTracker.occurrenceCount;
const href = searchTracker.occurrence[count] ?? null;
return (href !== null)
&& `${ match }`
|| match;
},
);
}
const string = "On dashboard, then open dashboard details, verify your dashboard details on data and other data";
const wordsArray = [
"dashboard",
"dashboard",
"data",
];
const occurrences = [1 , 3 , 2];
const linksArray = [
"https://abcd.com/login",
"https://abcd.com/home",
"https://abcd.com/data",
];
console.log(
'before ... ',
string,
'\n\nafter ... ',
safelyReplaceSearchOccurrencesWithRelatedHref(
string, wordsArray, linksArray, occurrences,
),
);
console.log({
replacementTracker: wordsArray
.reduce(aggregateReplacementTrackerFromBoundData, {
occurrences,
hrefList: linksArray,
tracker: {},
})
.tracker
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
The string I have is as like as follows
let a = "0j (0.001953125+0j) (-0.001953125+0.001953125j) (0.998046875+0j) (-0.001953125+0j) (0.001953125+0j) (0+0.0914587j)"
Info about the string:
1/ Each substring is complex number in the format of a+bj
2/ Possible format of the complex number could be a+bj,a,bj. Eg: 1+2j, 1,2j
3/ There is a space( ) between each substring
4/ I have seen that 0+bj(eg: 0+5j) or a+0j(eg: 5+0j) format is not possible/ created by the backend so this type of format/ presentation is not considered for my case.
5/ If the substring contains only real/imaginary part then parenthesis () will not be used. Eg: (5),(5j) is not possible. They will be 5,5j
I need to create a JSON or JavaScript object from that string which will be used to plot data. The data is coming from the Flask backend and it is different for each request. One approach I have found to make this JSON object is from an array which should look like
let my_array = [[0,0], [0.001953125,0], [-0.001953125,0.001953125], [0.998046875,0],[-0.001953125,0],[-0.001953125,0],[0,0.914587]]
But I am totally lost in making of this array. Initially, I have removed all the j from the string by a.replaceAll("j","") but then I have not found a way to make my desired array structure. If I get the array, I can make the JSON object with the following approach:
my_array = [[0,0], [0.001953125,0], [-0.001953125,0.001953125], [0.998046875,0],[-0.001953125,0],[-0.001953125,0],[0,0.914587]]
temp_key = ["i", "q"]
my_json = {
}
for(let a = 0; a < my_array.length; a++){
temp_json = {};
for(let b = 0; b < my_array[a].length; b++){
temp_json[temp_key[b]] = my_array[a][b];
}
my_json[String(a)] = temp_json;
}
console.log("my_json: ",my_json)
Suggestions regarding making this array will be appreciated.
You can split by whitespace, then use a regular expression to match digit characters in the substring (eg 0.001953125+0j to 0.001953125 and 0).
const str = "0j (0.001953125+0j) (-0.001953125+0.001953125j) (0.998046875+0j) (-0.001953125+0j) (0.001953125+0j) (0+0.914587j)";
const arr = str
.split(' ')
.map((substr) => {
const [real, imag = 0] = substr.match(/-?\d+(?:\.\d+)?/g).map(Number);
return [real, imag];
});
console.log(arr);
-?\d+(?:\.\d+)? is:
-? - possibly match a leading -
\d+ - match one or more digits
(?:\.\d+)? - optionally match the following (the decimal part of a number):
\. - a literal .
\d+ - one or more digits
I have the following string
"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,
I need to get string after "ssu":" the Result should be 89c4eef0-3a0d-47ae-a97f-42adafa7cf8f. How do I do it in Javascript but very simple? I am thinking to collect 36 character after "ssu":".
You could build a valid JSON string and parse it and get the wanted property ssu.
var string = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,',
object = JSON.parse(`{${string.slice(0, -1)}}`), // slice for removing the last comma
ssu = object.ssu;
console.log(ssu);
One solution would be to use the following regular expression:
/\"ssu\":\"([\w-]+)\"/
This pattern basically means:
\"ssu\":\" , start searching from the first instance of "ssu":"
([\w-]+) , collect a "group" of one or more alphanumeric characters \w and hypens -
\", look for a " at the end of the group
Using a group allows you to extract a portion of the matched pattern via the String#match method that is of interest to you which in your case is the guid that corresponds to ([\w-]+)
A working example of this would be:
const str = `"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,`
const value = str.match(/\"ssu\":\"([\w-]+)\"/)[1]
console.log(value);
Update: Extract multiple groupings that occour in string
To extract values for multiple occurances of the "ssu" key in your input string, you could use the String#matchAll() method to achieve that as shown:
const str = `"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,"ssu":"value-of-second-ssu","ssu":"value-of-third-ssu"`;
const values =
/* Obtain array of matches for pattern */
[...str.matchAll(/\"ssu\":\"([\w-]+)\"/g)]
/* Extract only the value from pattern group */
.map(([,value]) => value);
console.log(values);
Note that for this to work as expected, the /g flag must be added to the end of the original pattern. Hope that helps!
Use this regExp: /(?!"ssu":")(\w+-)+\w+/
const str = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,';
const re = /(?!"ssu":")(\w+-)+\w+/;
const res = str.match(re)[0];
console.log(res);
You can use regular expressions.
var str = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049,'
var minhaRE = new RegExp("[a-z|0-9]*-[a-z|0-9|-]*");
minhaRE.exec(str)
OutPut: Array [ "89c4eef0-3a0d-47ae-a97f-42adafa7cf8f" ]
Looks almost like a JSON string.
So with a small change it can be parsed to an object.
var str = '"sis":4,"sct":15,"ssu":"89c4eef0-3a0d-47ae-a97f-42adafa7cf8f","ssv":384,"siw":96554,"scx":1049, ';
var obj = JSON.parse('{'+str.replace(/[, ]+$/,'')+'}');
console.log(obj.ssu)
In my code I split a string based on _ and grab the second item in the array.
var element = $(this).attr('class');
var field = element.split('_')[1];
Takes good_luck and provides me with luck. Works great!
But, now I have a class that looks like good_luck_buddy. How do I get my javascript to ignore the second _ and give me luck_buddy?
I found this var field = element.split(new char [] {'_'}, 2); in a c# stackoverflow answer but it doesn't work. I tried it over at jsFiddle...
Use capturing parentheses:
'good_luck_buddy'.split(/_(.*)/s)
['good', 'luck_buddy', ''] // ignore the third element
They are defined as
If separator contains capturing parentheses, matched results are returned in the array.
So in this case we want to split at _.* (i.e. split separator being a sub string starting with _) but also let the result contain some part of our separator (i.e. everything after _).
In this example our separator (matching _(.*)) is _luck_buddy and the captured group (within the separator) is lucky_buddy. Without the capturing parenthesis the luck_buddy (matching .*) would've not been included in the result array as it is the case with simple split that separators are not included in the result.
We use the s regex flag to make . match on newline (\n) characters as well, otherwise it would only split to the first newline.
What do you need regular expressions and arrays for?
myString = myString.substring(myString.indexOf('_')+1)
var myString= "hello_there_how_are_you"
myString = myString.substring(myString.indexOf('_')+1)
console.log(myString)
I avoid RegExp at all costs. Here is another thing you can do:
"good_luck_buddy".split('_').slice(1).join('_')
With help of destructuring assignment it can be more readable:
let [first, ...rest] = "good_luck_buddy".split('_')
rest = rest.join('_')
A simple ES6 way to get both the first key and remaining parts in a string would be:
const [key, ...rest] = "good_luck_buddy".split('_')
const value = rest.join('_')
console.log(key, value) // good, luck_buddy
Nowadays String.prototype.split does indeed allow you to limit the number of splits.
str.split([separator[, limit]])
...
limit Optional
A non-negative integer limiting the number of splits. If provided, splits the string at each occurrence of the specified separator, but stops when limit entries have been placed in the array. Any leftover text is not included in the array at all.
The array may contain fewer entries than limit if the end of the string is reached before the limit is reached.
If limit is 0, no splitting is performed.
caveat
It might not work the way you expect. I was hoping it would just ignore the rest of the delimiters, but instead, when it reaches the limit, it splits the remaining string again, omitting the part after the split from the return results.
let str = 'A_B_C_D_E'
const limit_2 = str.split('_', 2)
limit_2
(2) ["A", "B"]
const limit_3 = str.split('_', 3)
limit_3
(3) ["A", "B", "C"]
I was hoping for:
let str = 'A_B_C_D_E'
const limit_2 = str.split('_', 2)
limit_2
(2) ["A", "B_C_D_E"]
const limit_3 = str.split('_', 3)
limit_3
(3) ["A", "B", "C_D_E"]
This solution worked for me
var str = "good_luck_buddy";
var index = str.indexOf('_');
var arr = [str.slice(0, index), str.slice(index + 1)];
//arr[0] = "good"
//arr[1] = "luck_buddy"
OR
var str = "good_luck_buddy";
var index = str.indexOf('_');
var [first, second] = [str.slice(0, index), str.slice(index + 1)];
//first = "good"
//second = "luck_buddy"
You can use the regular expression like:
var arr = element.split(/_(.*)/)
You can use the second parameter which specifies the limit of the split.
i.e:
var field = element.split('_', 1)[1];
Replace the first instance with a unique placeholder then split from there.
"good_luck_buddy".replace(/\_/,'&').split('&')
["good","luck_buddy"]
This is more useful when both sides of the split are needed.
I need the two parts of string, so, regex lookbehind help me with this.
const full_name = 'Maria do Bairro';
const [first_name, last_name] = full_name.split(/(?<=^[^ ]+) /);
console.log(first_name);
console.log(last_name);
Non-regex solution
I ran some benchmarks, and this solution won hugely:1
str.slice(str.indexOf(delim) + delim.length)
// as function
function gobbleStart(str, delim) {
return str.slice(str.indexOf(delim) + delim.length);
}
// as polyfill
String.prototype.gobbleStart = function(delim) {
return this.slice(this.indexOf(delim) + delim.length);
};
Performance comparison with other solutions
The only close contender was the same line of code, except using substr instead of slice.
Other solutions I tried involving split or RegExps took a big performance hit and were about 2 orders of magnitude slower. Using join on the results of split, of course, adds an additional performance penalty.
Why are they slower? Any time a new object or array has to be created, JS has to request a chunk of memory from the OS. This process is very slow.
Here are some general guidelines, in case you are chasing benchmarks:
New dynamic memory allocations for objects {} or arrays [] (like the one that split creates) will cost a lot in performance.
RegExp searches are more complicated and therefore slower than string searches.
If you already have an array, destructuring arrays is about as fast as explicitly indexing them, and looks awesome.
Removing beyond the first instance
Here's a solution that will slice up to and including the nth instance. It's not quite as fast, but on the OP's question, gobble(element, '_', 1) is still >2x faster than a RegExp or split solution and can do more:
/*
`gobble`, given a positive, non-zero `limit`, deletes
characters from the beginning of `haystack` until `needle` has
been encountered and deleted `limit` times or no more instances
of `needle` exist; then it returns what remains. If `limit` is
zero or negative, delete from the beginning only until `-(limit)`
occurrences or less of `needle` remain.
*/
function gobble(haystack, needle, limit = 0) {
let remain = limit;
if (limit <= 0) { // set remain to count of delim - num to leave
let i = 0;
while (i < haystack.length) {
const found = haystack.indexOf(needle, i);
if (found === -1) {
break;
}
remain++;
i = found + needle.length;
}
}
let i = 0;
while (remain > 0) {
const found = haystack.indexOf(needle, i);
if (found === -1) {
break;
}
remain--;
i = found + needle.length;
}
return haystack.slice(i);
}
With the above definition, gobble('path/to/file.txt', '/') would give the name of the file, and gobble('prefix_category_item', '_', 1) would remove the prefix like the first solution in this answer.
Tests were run in Chrome 70.0.3538.110 on macOSX 10.14.
Use the string replace() method with a regex:
var result = "good_luck_buddy".replace(/.*?_/, "");
console.log(result);
This regex matches 0 or more characters before the first _, and the _ itself. The match is then replaced by an empty string.
Javascript's String.split unfortunately has no way of limiting the actual number of splits. It has a second argument that specifies how many of the actual split items are returned, which isn't useful in your case. The solution would be to split the string, shift the first item off, then rejoin the remaining items::
var element = $(this).attr('class');
var parts = element.split('_');
parts.shift(); // removes the first item from the array
var field = parts.join('_');
Here's one RegExp that does the trick.
'good_luck_buddy' . split(/^.*?_/)[1]
First it forces the match to start from the
start with the '^'. Then it matches any number
of characters which are not '_', in other words
all characters before the first '_'.
The '?' means a minimal number of chars
that make the whole pattern match are
matched by the '.*?' because it is followed
by '_', which is then included in the match
as its last character.
Therefore this split() uses such a matching
part as its 'splitter' and removes it from
the results. So it removes everything
up till and including the first '_' and
gives you the rest as the 2nd element of
the result. The first element is "" representing
the part before the matched part. It is
"" because the match starts from the beginning.
There are other RegExps that work as
well like /_(.*)/ given by Chandu
in a previous answer.
The /^.*?_/ has the benefit that you
can understand what it does without
having to know about the special role
capturing groups play with replace().
if you are looking for a more modern way of doing this:
let raw = "good_luck_buddy"
raw.split("_")
.filter((part, index) => index !== 0)
.join("_")
Mark F's solution is awesome but it's not supported by old browsers. Kennebec's solution is awesome and supported by old browsers but doesn't support regex.
So, if you're looking for a solution that splits your string only once, that is supported by old browsers and supports regex, here's my solution:
String.prototype.splitOnce = function(regex)
{
var match = this.match(regex);
if(match)
{
var match_i = this.indexOf(match[0]);
return [this.substring(0, match_i),
this.substring(match_i + match[0].length)];
}
else
{ return [this, ""]; }
}
var str = "something/////another thing///again";
alert(str.splitOnce(/\/+/)[1]);
For beginner like me who are not used to Regular Expression, this workaround solution worked:
var field = "Good_Luck_Buddy";
var newString = field.slice( field.indexOf("_")+1 );
slice() method extracts a part of a string and returns a new string and indexOf() method returns the position of the first found occurrence of a specified value in a string.
This should be quite fast
function splitOnFirst (str, sep) {
const index = str.indexOf(sep);
return index < 0 ? [str] : [str.slice(0, index), str.slice(index + sep.length)];
}
console.log(splitOnFirst('good_luck', '_')[1])
console.log(splitOnFirst('good_luck_buddy', '_')[1])
This worked for me on Chrome + FF:
"foo=bar=beer".split(/^[^=]+=/)[1] // "bar=beer"
"foo==".split(/^[^=]+=/)[1] // "="
"foo=".split(/^[^=]+=/)[1] // ""
"foo".split(/^[^=]+=/)[1] // undefined
If you also need the key try this:
"foo=bar=beer".split(/^([^=]+)=/) // Array [ "", "foo", "bar=beer" ]
"foo==".split(/^([^=]+)=/) // [ "", "foo", "=" ]
"foo=".split(/^([^=]+)=/) // [ "", "foo", "" ]
"foo".split(/^([^=]+)=/) // [ "foo" ]
//[0] = ignored (holds the string when there's no =, empty otherwise)
//[1] = hold the key (if any)
//[2] = hold the value (if any)
a simple es6 one statement solution to get the first key and remaining parts
let raw = 'good_luck_buddy'
raw.split('_')
.reduce((p, c, i) => i === 0 ? [c] : [p[0], [...p.slice(1), c].join('_')], [])
You could also use non-greedy match, it's just a single, simple line:
a = "good_luck_buddy"
const [,g,b] = a.match(/(.*?)_(.*)/)
console.log(g,"and also",b)