Differences between decodeURI and decodeURIComponent
The main differences are:
So, in encodeURIComponent these separators are encoded also because they are regarded as text and not special characters.
Now back to the difference between the decode functions, each function decodes strings generated by its corresponding encode counterpart taking care of the semantics of the special characters and their handling.
so in your case decodeURIComponent does the job
Differences between decodeURI and decodeURIComponent
The main differences are:
So, in encodeURIComponent these separators are encoded also because they are regarded as text and not special characters.
Now back to the difference between the decode functions, each function decodes strings generated by its corresponding encode counterpart taking care of the semantics of the special characters and their handling.
so in your case decodeURIComponent does the job
Use decodeURIComponent:
var decoded = decodeURIComponent(foo);
decodeURI has some issues as you are seeing. decodeURIComponent is the best practice tool for this job.
javascript - Decode a run-length encoded string - Stack Overflow
Blueprint String decoder in Javascript?
Replace Unicode in a string with its symbol...
GDPR Cookie decoding
You could replace the string with a regular expression and get the wanted nested replacements until no more strings are available to replace.
const decodeString = string => {
let repeat
do {
repeat = false;
string = string.replace(/(\d+)\[([^\[\]]+)\]/g, (_, c, v) => {
repeat = true;
return v.repeat(c);
});
} while (repeat);
return string;
}
console.log(decodeString("3[a]2[bc]")); // "aaabcbc"
console.log(decodeString("3[a2[c]]")); // "accaccacc"
console.log(decodeString("2[abc]3[cd]ef")); // "abcabccdcdcdef"
console.log(decodeString("abc3[cd]xyz")); // "abccdcdcdxyz"
Run code snippetEdit code snippet Hide Results Copy to answer Expand
If you wish to simplify/update/explore the expression, it's been explained on the top right panel of regex101.com. You can watch the matching steps or modify them in this debugger link, if you'd be interested. The debugger demonstrates that how a RegEx engine might step by step consume some sample input strings and would perform the matching process.
RegEx Circuit
jex.im visualizes regular expressions:

This answer is creative and good; we can also use stack for solving this problem.
This'll get accepted:
const decodeString = s => {
const stack = [];
for (const char of s) {
if (char !== "]") {
stack.push(char);
continue;
}
let currChar = stack.pop();
let decoded = '';
while (currChar !== '[') {
decoded = currChar.concat(decoded);
currChar = stack.pop();
}
let num = '';
currChar = stack.pop();
while (!Number.isNaN(Number(currChar))) {
num = currChar.concat(num);
currChar = stack.pop();
}
stack.push(currChar);
stack.push(decoded.repeat(Number(num)));
}
return stack.join('');
};
console.log(decodeString("3[a]2[bc]"))
console.log(decodeString("3[a2[c]]"))
console.log(decodeString("2[abc]3[cd]ef"))
console.log(decodeString("abc3[cd]xyz"))
Run code snippetEdit code snippet Hide Results Copy to answer Expand
In Python, we would similarly use a list, which is very similar to JavaScript's array:
class Solution:
def decodeString(self, base_string):
stack = []
decoded = ''
full_num = 0
for char in base_string:
if char == '[':
stack.append(decoded)
stack.append(full_num)
decoded, full_num = '', 0
elif char == ']':
curr_digit, curr_char = stack.pop(), stack.pop()
decoded = curr_char + curr_digit * decoded
elif char.isdigit():
full_num *= 10
full_num += int(char)
else:
decoded += char
return decoded
In Java, we would have used two Stacks:
class Solution {
public String decodeString(String string) {
String decoded = "";
Stack<Integer> numberStack = new Stack<>();
Stack<String> decodedStack = new Stack<>();
int count = 0;
while (count < string.length()) {
if (Character.isDigit(string.charAt(count))) {
int fullNum = 0;
while (Character.isDigit(string.charAt(count))) {
fullNum = 10 * fullNum + (string.charAt(count) - '0');
count++;
}
numberStack.push(fullNum);
} else if (string.charAt(count) == '[') {
decodedStack.push(decoded);
decoded = "";
count++;
} else if (string.charAt(count) == ']') {
StringBuilder temp = new StringBuilder(decodedStack.pop());
int repeatTimes = numberStack.pop();
for (int iter = 0; iter < repeatTimes; iter++)
temp.append(decoded);
decoded = temp.toString();
count++;
} else
decoded += string.charAt(count++);
}
return decoded;
}
}
References
- For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.