lets say the input is
let word = 'I Lo1ve Co4ding'
the output would be I Loove Coooooding
so repeating x
letters after putting a number after
Still don't understand how it works and how to replace it mid string.
lets say the input is
let word = 'I Lo1ve Co4ding'
the output would be I Loove Coooooding
so repeating x
letters after putting a number after
Still don't understand how it works and how to replace it mid string.
You can use the callback function argument in String.prototype.replace
, and call String.prototype.repeat
on the first matching group (letter) and pass the second matching group (number) plus 1.
const expandStr = (str) =>
str.replace(/([a-z])(\d+)/gi, (g, g1, g2) => g1.repeat(+g2 + 1));
console.log(expandStr('I Lo1ve Co4ding'));
As suggested in the comments, you may use the following:
/(\p{L})(\p{N}+)/gu
In place of:
/([a-z])(\d+)/gi
Explanation:
\p{L}
– matches a single code point in the category "letter"\p{N}
– matches any kind of numeric character in any script\p{S}
– symbols e.g. emojiconst expandStr = (str) =>
str.replace(/(\p{L}|\p{S})(\p{N}+)/gu, (g, g1, g2) => g1.repeat(+g2 + 1));
console.log(expandStr('I Lo1ve Co4ding'));
console.log(expandStr('I give ️ I saw 1!')); // Works with emoji
Please refer to "Unicode Categories" to learn more.
Alternative pattern: /([^(\p{N}|\s)])(\p{N}+)/gu
Here is a more traditional example that incorporates loops. It does not use regular expressions, but follows a tokenizer (parser) approach.
Note: Keep in mind that this naïve example does not account for Unicode.
const
NUMBER_RANGE_START = '0' .charCodeAt(0), // 48
NUMBER_RANGE_END = '9' .charCodeAt(0), // 57
LETTER_UPPER_RANGE_START = 'A' .charCodeAt(0), // 65
LETTER_UPPER_RANGE_END = 'Z' .charCodeAt(0), // 90
LETTER_LOWER_RANGE_START = 'a' .charCodeAt(0), // 97
LETTER_LOWER_RANGE_END = 'z' .charCodeAt(0), // 122
WHITESPACE_CARRIAGE_RETURN = '\r'.charCodeAt(0), // 13
WHITESPACE_LINE_FEED = '\n'.charCodeAt(0), // 10
WHITESPACE_SPACE = ' ' .charCodeAt(0), // 32
WHITESPACE_TAB = '\t'.charCodeAt(0); // 9
const codeInRange = (code, start, end) => code >= start && code <= end;
const charInRange = (char, start, end) => codeInRange(char.charCodeAt(0), start, end);
const isNumber = (char) =>
charInRange(char, NUMBER_RANGE_START, NUMBER_RANGE_END);
const isUpperLetter = (char) =>
charInRange(char, LETTER_UPPER_RANGE_START, LETTER_UPPER_RANGE_END);
const isLowerLetter = (char) =>
charInRange(char, LETTER_LOWER_RANGE_START, LETTER_LOWER_RANGE_END);
const isLetter = (char) => isLowerLetter(char) || isUpperLetter(char);
const isWhiteSpace = (char) => {
switch (char.charCodeAt(0)) {
case WHITESPACE_CARRIAGE_RETURN:
case WHITESPACE_LINE_FEED:
case WHITESPACE_SPACE:
case WHITESPACE_TAB:
return true;
default:
return false;
}
};
const expandStr = (str) => {
const result = [];
let index, char, prevChar, count, step;
for (index = 0; index < str.length; index++) {
char = str[index];
if (
isNumber(char) &&
(
isLetter(prevChar) ||
(
!isWhiteSpace(prevChar) &&
!isNumber(prevChar)
)
)
) {
count = parseInt(char, 10);
for (step = 0; step < count; step++) {
result.push(prevChar);
}
} else {
result.push(char);
}
prevChar = char;
}
return result.join('');
};
console.log(expandStr('I Lo1ve Co4ding')); // I Loove Coooooding
A little bit longer way as from Mr.Polywhirl. But I think foreach loops make for good readability and you will see how it works.
const word = 'I Lo1ve Co4ding'
function rewrite(w) {
const arr = [...w];
let n = [];
arr.forEach((s,i) => {
if(! isNaN(s) && s != ' ') {
n.push(arr[i-1].repeat(s));
} else {
n.push(s);
}
});
return n.join('');
}
console.log( rewrite(word) );