0

Dealing with a string === "1$$$2!@!@3!@!@4!@!@5". I want to be able to split it at both $$$ and !@!@ which are custom delimiters that have been passed in. Since I have to be able to take in any custom delimiter I can't simply use a regex that only pulls out the numbers b/c I could deal with a custom delimiter such as [r9r] which I need to split by.

delimiter = delimiter.substring(0, delimiter.length - 1);
console.log(delimiter) // => "$$$|!@!@"
  const regex = new RegExp(`(,|\\n|\\${delimiter})`,'g');
  const finalStr = str.substring(str.indexOf('\n'), str.length)
  console.log(finalStr); // => "1$$$2!@!@3!@!@45"
  let arr = finalStr.split(regex).filter(Boolean);
  console.log(arr); // => ["1$$$2", "!@!@", "3", "!@!@", "4", "!@!@", "5"], why does '$$$' stay attached to the 1 and 2?
  const finalArr = [];
  for (let char of arr) {
    if (parseInt(char)) {
      finalArr.push(char);
    }
  }
  console.log(finalArr) // => ["1$$$2", "3", "4", "5"]
  return finalArr;

I want my final array to be: ["1", "2", "3", "4", "5"] but for some reason the '$$$' doesn't get split like the '!@!@' delimiter does. When I used '!!!' instead of '$$$' it worked so I assume its a special character but still couldn't find a way to accept it.

Joe Spinelli
  • 105
  • 1
  • 11
  • I'm not entirely sure if this is the reason, but in regex the $-sign means "end of line". You could escape the $$$ as \$\$\$ and try to use it this way. – Christiaan Nieuwlaat Oct 03 '19 at 08:01
  • 1
    Are you aware `$` has special meaning in regex? try `"1$$$2!@!@3!@!@4!@!@5".split(/\$\$\$|!@!@/)` – Mat J Oct 03 '19 at 08:01
  • Are you sure you need to split using those delimiters ? If you need the numbers, you can simply match like this : `"1$$$2!@!@3!@!@4!@!@5".match(/\d+/g)` – Seblor Oct 03 '19 at 08:04
  • @ChristiaanNieuwlaat I have to be able to take in any length of any combination of characters to how would I insert that '\' between every single character inside my regex? – Joe Spinelli Oct 03 '19 at 08:05
  • @Seblor well I have to be able to take in any custom delimiter so for example that could be something like [r9r] which means I can't only take the numbers out it has to be that specific delimiter. – Joe Spinelli Oct 03 '19 at 08:06
  • @JoeSpinelli, you'll have to replace every $ with \$. Maybe you could do this with string.replace function? – Christiaan Nieuwlaat Oct 03 '19 at 08:08

3 Answers3

2

Your template string looks like this (,|\\n|\\${delimiter}).

If your delimiter is "$$$", then when your template string is converted to a regular string it will look like this: (,|\\n|\\$$$)

Your first $ in the regex will be interpreted as a literal, but the other two are interpreted as regex characters meaning the end of the line. You need to escape the characters in your delimited before building your regex with them. You can do this by hand or try the escape-string-regexp library.

See also the related SO answer here.

That being said, your use of Regex here might not be warranted. It may be faster to search the string using indexOf with 3 successive calls, one for each of , \n and your delimited. That way you don't have to do any escaping and your code may even be faster.

Codebling
  • 10,764
  • 2
  • 38
  • 66
1

$ is a special character in Regex. It means "End of string", so you have to escape.

[Edited] I guess that you want to "pass" delimiters from users, so I changed to the function to receive "Array of delimiters" and escape special characters.

function escapeRegex(r) {
  return r.replace(/\W/g,r=>"\\"+r);// Replace only non-alphabet  
}

function mySplit(delimiters,str) {
  let delimiter =  delimiters.map(escapeRegex).join("|");

  console.log(delimiter) // => "\$|!@"
  const regex = new RegExp(`(,|\\n|${delimiter})`,'g');
  console.log(regex);
  const finalStr = str;
  console.log(finalStr); // => "1$$$2!@!@3!@!@45"
  let arr = finalStr.split(regex).filter(Boolean);
  console.log(arr); // => ["1", "$", "$", "$", "2", "!@", "!@", "3", "!@", "!@", "4", "!@", "!@", "5"]
  const finalArr = [];
  for (let char of arr) {
    let n=parseInt(char);
    if (n===n) {// check NaN
      finalArr.push(n);
    }
  }
  console.log(finalArr) // => [1,2, 3, 4, 5]
  return finalArr;
}
function parse(input) {
  const lines=input.split("\n");
  const delims=lines.shift();
  const str=lines.join("\n");
  const delimArray=[];
  delims.replace(/\[([^\]]+)\]/g, (_,c)=>delimArray.push(c));
  mySplit(delimArray,str);
}

parse('[$$$][!@!@]\n1$$$2!@!@3,4\n5');
parse("[*][!!][r9r]\n11r9r22*33!!44");

hoge1e3
  • 802
  • 5
  • 15
  • thing is I have to be able to account for any length and combination of characters as a custom delimiter so creating: delimiter = "\\$\\$\\$|!@!@"; would only work for this specific case but not others. – Joe Spinelli Oct 03 '19 at 08:12
  • I edited the code. Please check again. – hoge1e3 Oct 03 '19 at 08:32
  • the user just passes in a whole string "[$][!@]\n1$$$2!@!@3!@!@4!@!@5" in format: //[{delimiter1}][{delimiter2}]...\n{numbers}. So the delimiters are in brackets and followed by '\n' but everything is a character of the string passed in. – Joe Spinelli Oct 03 '19 at 08:59
  • works for this example but doesn't for a string like: "[*][!!][r9r]\n11r9r22*33!!44" which should return 110 but instead does 29. – Joe Spinelli Oct 03 '19 at 09:07
  • Re-edited. It seems to be work as long as the given examples. – hoge1e3 Oct 03 '19 at 12:16
  • I really appreciate your help! With all these delimiters I still have to always allow ' \n ' and ' , ' as delimiters too so for example with: '[$$$][!@!@]\n1$$$2!@!@3,4\n5' it splits off the 5 at the end and returns => [1, 2, 3, 4] instead. Anyway to only account for that first ' \n ' ? – Joe Spinelli Oct 03 '19 at 15:11
  • Multi-line input is also supported. – hoge1e3 Oct 05 '19 at 03:38
0
finalStr.split(new RegExp('!@!@|\\$\\$\\$'))
Horatiu Jeflea
  • 7,256
  • 6
  • 38
  • 67