JS / TS splitting string by a delimiter without removing the delimiter - javascript

I have a string that I need to split by a certain delimiter and convert into an array, but without removing the delimiter itself.
For example, consider the following code:
var str = "#mavic#phantom#spark";
str.split("#") //["", "mavic", "phantom", "spark"]
I need the output to be as follows:
["#mavic", "#phantom", "#spark"]
I read here but that does not answer my question.

You could split by positive lookahead of #.
var string = "#mavic#phantom#spark",
splitted = string.split(/(?=#)/);
console.log(splitted);

Split the string by # and use the reduce to return the modified string
var str = "#mavic#phantom#spark";
let x = str.split("#").reduce((acc, curr) => {
if (curr !== '') {
acc.push('#' + curr);
}
return acc;
}, [])
console.log(x)

Here is also some non-regexp methods of solving your task:
Solution 1 classical approach - iterate over the string and each time when we find indexOf our delimiter, we push to the result array the substring between current position and the next position. In the else block we have a case for the last substring - we simply add it to the result array and break the loop.
const delimiter = '#';
const result1 = [];
let i = 0;
while (i < str.length) {
const nextPosition = str.indexOf(delimiter, i+1);
if (nextPosition > 0) {
result1.push(str.substring(i, nextPosition));
i = nextPosition;
} else {
result1.push(str.substring(i));
break;
}
}
Solution 2 - split the initial string starting at index 1 (in order to not include empty string in the result array) and then just map the result array by concatenating the delimiter and current array item.
const result2 = str.substr(1).split(delimiter).map(s => delimiter + s);

another way:
filter empty elements after splitting, and map these elements to start with the character you splitted with.
string.split("#").filter((elem) => elem).map((elem) => "#" + elem);

Related

How to extract certain string characters in Javascript in a generic way?

I am trying to extract a string value, but I need a generic code to extract the values.
INPUT 1 : "/rack=1/shelf=1/slot=12/port=200"
INPUT 2 : "/shelf=1/slot=13/port=3"
INPUT 3 : "/shelf=1/slot=142/subslot=2/port=4"
I need the below output:
OUTPUT 1 : "/rack=1/shelf=1/slot=12"
OUTPUT 2 : "/shelf=1/slot=13"
OUTPUT 3 : "/shelf=1/slot=142"
Basically I am trying to extract up to the slot value. I tried indexOf and substr, but those are specific to individual string values. I require a generic code to extract up to slot. Is there a way how I can match the numeric after the slot and perform extraction?
We can try matching on the following regular expression, which captures all content we want to appear in the output:
^(.*\/shelf=\d+\/slot=\d+).*$
Note that this greedily captures all content up to, and including, the /shelf followed by /slot portions of the input path.
var inputs = ["/rack=1/shelf=1/slot=12/port=200", "/shelf=1/slot=13/port=3", "/shelf=1/slot=142/subslot=2/port=4"];
for (var i=0; i < inputs.length; ++i) {
var output = inputs[i].replace(/^(.*\/shelf=\d+\/slot=\d+).*$/, "$1");
console.log(inputs[i] + " => " + output);
}
You could use this function. If "subslot" is always after "slot" then you can remove the "/" in indexOf("/slot")
function exractUptoSlot(str) {
return str.substring(0,str.indexOf("/",str.indexOf("/slot")));
}
If it will always be the last substring, you could use slice:
function removeLastSubStr(str, delimiter) {
const splitStr = str.split(delimiter);
return splitStr
.slice(0, splitStr.length - 1)
.join(delimiter);
}
const str = "/rack=1/shelf=1/slot=12/port=200";
console.log(
removeLastSubStr(str, '/')
)
if you don't know where your substring is, but you know what it is you could filter it out of the split array:
function removeSubStr(str, delimiter, substr) {
const splitStr = str.split(delimiter);
return splitStr
.filter(s => !s.contains(substr))
.join(delimiter);
}
const str = "/rack=1/shelf=1/slot=12/port=200";
console.log(
removeSubStr(str, '/', 'port=200')
)
console.log(
removeSubStr(str, '/', 'port')
)

Split after regex max without losing delimeter

I'd like to transform a string like:
hello!world.what?up into ["hello!", "world.", "what?", "up"]
.split(/[?=<\.\?\!>]+/) is close to what I'm after, which returns:
["hello", "world", "what", "up"]
.split(/(?=[\?\!\.])/) is a bit closer yet, which returns:
["hello", "!world", ".what", "?up"]
This does the trick, but it's not pretty:
.split(/(?=[\?\!\.])/).map((s, idx, arr) => { (idx > 0) s = s.slice(1); return idx < arr.length - 1 ? s + arr[idx+1][0] : s }).filter(s => s)
How would I rephrase this to achieve the desired output?
Edit: Updated question.
Not sure of the real requirement but to accomplish what you want you could use .match instead of .split.
const items =
'hello!world.what?'.match(/\w+\W/g);
console.log(items);
update after comment
You could add a group for any character you want to use as the terminator for each part.
const items =
'hello!world.what?'.match(/\w+[!.?]/g);
console.log(items);
additional update
the previous solution would only select alphanumeric chars before the !.?
If you want to match any char except the delimiters then use
const items =
'hello!world.what?up'.match(/[^!.?]+([!.?]|$)/g);
console.log(items);
One solution could be first to use replace() for add a token after each searched character, then you can split by this token.
let input = "hello!world.what?";
const customSplit = (str) =>
{
let token = "#";
return str.replace(/[!.?]/g, (match) => match + "#")
.split(token)
.filter(Boolean);
}
console.log(customSplit(input));

Convert a string to array of number and alphabets

var string;
var splitstring = string.split("????");
my string is 12BLG123
i need the array splitstring to have elements 12,BLG,123
(The alphabets and numbers randomly vary)
const string = `12BLG123`
const splitString = string.split(/(\d+)/).filter(i => i)
console.log(splitString)
The regex splits the string by numeric strings. Since split doesn't include the value that it is being split by, we use the capturing syntax to include the numeric strings. Empty strings are introduced if the string starts or ends with numeric strings so we use filter(i => i) to remove the empty strings (it works because empty strings are falsey values in javascript).
Though not regex or split, but you can do something like this,
var str = "12BLG123";
var result = [].reduce.call(str, (acc, a) => {
if (!acc.length) return [a]; // initial case
let last = acc[acc.length - 1];
// same type (digit or char)
if (isNaN(parseInt(a, 10)) == isNaN(parseInt(last.charAt(0), 10)))
acc[acc.length - 1] = last + a;
// different type
else acc.push(a);
// return the accumulative
return acc;
}, [] /* the seed */);
console.log(result);
This regex will probably work.
var splitString = string.split("[^A-Z0-9]+|(?<=[A-Z])(?=[0-9])|(?<=[0-9])(?=[A-Z])");

How to capitalize the last letter of each word in a string

I am still rather new to JavaScript and I am having an issue of getting the first character of the string inside the array to become uppercase.
I have gotten to a point where I have gotten all the texted lowercase, reversed the text character by character, and made it into a string. I need to get the first letter in the string to uppercase now.
function yay () {
var input = "Party like its 2015";
return input.toLowerCase().split("").reverse().join("").split(" ");
for(var i = 1 ; i < input.length ; i++){
input[i] = input[i].charAt(0).toUpperCase() + input[i].substr(1);
}
}
console.log(yay());
I need the output to be "partY likE itS 2015"
Frustrating that you posted your initial question without disclosing the desired result. Lots of turmoil because of that. Now, that the desired result is finally clear - here's an answer.
You can lowercase the whole thing, then split into words, rebuild each word in the array by uppercasing the last character in the word, then rejoin the array:
function endCaseWords(input) {
return input.toLowerCase().split(" ").map(function(item) {
return item.slice(0, -1) + item.slice(-1).toUpperCase();
}).join(" ");
}
document.write(endCaseWords("Party like its 2015"));
Here's a step by step explanation:
Lowercase the whole string
Use .split(" ") to split into an array of words
Use .map() to iterate the array
For each word, create a new word that is the first part of the word added to an uppercased version of the last character in the word
.join(" ") back together into a single string
Return the result
You could also use a regex replace with a custom callback:
function endCaseWords(input) {
return input.toLowerCase().replace(/.\b/g, function(match) {
return match.toUpperCase();
});
}
document.write(endCaseWords("Party like its 2015"));
FYI, there are lots of things wrong with your original code. The biggest mistake is that as soon as you return in a function, no other code in that function is executed so your for loop was never executed.
Then, there's really no reason to need to reverse() the characters because once you split into words, you can just access the last character in each word.
Instead of returning the result splitting and reversing the string, you need to assign it to input. Otherwise, you return from the function before doing the loop that capitalizes the words.
Then after the for loop you should return the joined string.
Also, since you've reverse the string before you capitalize, you should be capitalizing the last letter of each word. Then you need to reverse the array before re-joining it, to get the words back in the original order.
function yay () {
var input = "Party like its 2015";
input = input.toLowerCase().split("").reverse().join("").split(" ");
for(var i = 1 ; i < input.length ; i++){
var len = input[i].length-1;
input[i] = input[i].substring(0, len) + input[i].substr(len).toUpperCase();
}
return input.reverse().join(" ");
}
alert(yay());
You can use regular expression for that:
input.toLowerCase().replace(/[a-z]\b/g, function (c) { return c.toUpperCase() });
Or, if you can use arrow functions, simply:
input.toLowerCase().replace(/[a-z]\b/g, c => c.toUpperCase())
Here's what I would do:
Split the sentence on the space character
Transform the resulting array using .map to capitalize the first character and lowercase the remaining ones
Join the array on a space again to get a string
function yay () {
var input = "Party like its 2015";
return input.split(" ").map(function(item) {
return item.charAt(0).toUpperCase() + item.slice(1).toLowerCase();
}).join(" ");
}
console.log(yay());
Some ugly, but working code:
var text = "Party like its 2015";
//partY likE itS 2015
function yay(input) {
input = input.split(' ');
arr = [];
for (i = 0; i < input.length; i++) {
new_inp = input[i].charAt(0).toLowerCase() + input[i].substring(1, input[i].length - 1) + input[i].charAt(input[i].length - 1).toUpperCase();
arr.push(new_inp);
}
str = arr.join(' ');
return str;
}
console.log(yay(text));
Try using ucwords from PHP.js. It's quite simple, actually.
String.prototype.ucwords = function() {
return (this + '')
.replace(/^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g, function($1) {
return $1.toUpperCase();
});
}
var input = "Party like its 2015";
input = input.charAt(0).toLowerCase() + input.substr(1);
input = input.split('').reverse().join('').ucwords();
input = input.split('').reverse().join('');
Note: I modified their function to be a String function so method chaining would work.
function yay(str)
{
let arr = str.split(' ');
let farr = arr.map((item) =>{
let x = item.split('');
let len = x.length-1
x[len] = x[len].toUpperCase();
x= x.join('')
return x;
})
return farr.join(' ')
}
var str = "Party like its 2015";
let output = yay(str);
console.log(output) /// "PartY likE itS 2015"
You can split and then map over the array perform uppercase logic and retun by joining string.
let string = "Party like its 2015";
const yay = (string) => {
let lastCharUpperCase = string.split(" ").map((elem) => {
elem = elem.toLowerCase();
return elem.replace(elem[elem.length - 1], elem[elem.length - 1].toUpperCase())
})
return lastCharUpperCase.join(" ");
}
console.log(yay(string))

Cutting a string at nth occurrence of a character

What I want to do is take a string such as "this.those.that" and get a substring to or from the nth occurrence of a character. So, from the start of the string to the 2nd occurrence of . would return "this.those". Likewise, from the 2nd occurrence of . to the end of the string would return "that". Sorry if my question is foggy, it's not that easy to explain. Also, please do not suggest making extra variables, and the result will be in a string and not an array.
You could do it without arrays, but it would take more code and be less readable.
Generally, you only want to use as much code to get the job done, and this also increases readability. If you find this task is becoming a performance issue (benchmark it), then you can decide to start refactoring for performance.
var str = 'this.those.that',
delimiter = '.',
start = 1,
tokens = str.split(delimiter).slice(start),
result = tokens.join(delimiter); // those.that
console.log(result)
// To get the substring BEFORE the nth occurence
var tokens2 = str.split(delimiter).slice(0, start),
result2 = tokens2.join(delimiter); // this
console.log(result2)
jsFiddle.
Try this :
"qwe.fs.xczv.xcv.xcv.x".replace(/([^\.]*\.){3}/, '');
"xcv.xcv.x"
"qwe.fs.xczv.xcv.xcv.x".replace(/([^\.]*\.){**nth**}/, ''); - where is nth is the amount of occurrence to remove.
I'm perplexed as to why you want to do things purely with string functions, but I guess you could do something like the following:
//str - the string
//c - the character or string to search for
//n - which occurrence
//fromStart - if true, go from beginning to the occurrence; else go from the occurrence to the end of the string
var cut = function (str, c, n, fromStart) {
var strCopy = str.slice(); //make a copy of the string
var index;
while (n > 1) {
index = strCopy.indexOf(c)
strCopy = strCopy.substring(0, index)
n--;
}
if (fromStart) {
return str.substring(0, index);
} else {
return str.substring(index+1, str.length);
}
}
However, I'd strongly advocate for something like alex's much simpler code.
Just in case somebody needs both "this" and "those.that" in a way as alex described in his comment, here is a modified code:
var str = 'this.those.that',
delimiter = '.',
start = 1,
tokens = str.split(delimiter),
result = [tokens.slice(0, start), tokens.slice(start)].map(function(item) {
return item.join(delimiter);
}); // [ 'this', 'those.that' ]
document.body.innerHTML = result;
If you really want to stick to string methods, then:
// Return a substring of s upto but not including
// the nth occurence of c
function getNth(s, c, n) {
var idx;
var i = 0;
var newS = '';
do {
idx = s.indexOf(c);
newS += s.substring(0, idx);
s = s.substring(idx+1);
} while (++i < n && (newS += c))
return newS;
}

Categories