Splitting a string like "__f__g_f_" Javascript

Viewed 37

Say I have a string __f__g_f_

How can I achieve splitting it up to an array like ['__','f','__','g','_','f','_']

4 Answers

This should do:

const str = '__f__g_f_'

const parts = str.split(/([a-z]+)/)

console.log(parts)

Instead of using .split() you can use .match() with a matching group in the regex, it will give you an array of all your wanted matches.

const str = '__f__g_f_'
const parts = str.match(/(_+)|([a-z]+)/g)
console.log(parts);
[
  "__",
  "f",
  "__",
  "g",
  "_",
  "f",
  "_"
]

Split works at O(N) time complexity so you can write your own implementation and it is more readable and more maintainable

const s = "__f__g_f_"
const array = []

let buffer = ""
for (let i = 0; i < s.length; i++) {

    if (s[i] === "_") {
        buffer += s[i]
        continue
    }

    if (buffer.length > 0) {
        array.push(buffer)
        buffer = ""
    }
    array.push(s[i])
}
if (buffer.length > 0) {
    array.push(buffer)
}
console.log(array)

Edit:

(/([a-z]+)/) is elegant but always be in the shoes of other developers. What does (/([a-z]+)/) mean at a glance ? Regex is like a compiled program, machine code. unless all developers are adept in regex, They are not self-documented. They require to be commented on. And there might have bugs in them, how can you trust /([a-z]+)/ if it actually works without running the code? Seeing human readable code is always preferable. And finally, you may be surprised that regex can have weird time complexity, sometimes they jump to exponential. You don't know how they are implemented. Here, a simple plain and readable implementation is 100% faster than the regex.

console.time('regex');
for (let i = 0; i < 100_000_000; i++) {
  const str = '__f__g_f_'
  const parts = str.split(/([a-z]+)/)
}
console.timeEnd("regex")


console.time('plain_fast');

for (let i = 0; i < 100_000_000; i++) {
  const s = "__f__g_f_"
  const array = []

  let buffer = ""
  for (let i = 0; i < s.length; i++) {

    if (s[i] === "_") {
      buffer += s[i]
      continue
    }

    if (buffer.length > 0) {
      array.push(buffer)
      buffer = ""
    }
    array.push(s[i])
  }
  if (buffer.length > 0) {
    array.push(buffer)
  }
}
console.timeEnd("plain_fast")

regex: 10540.700ms
plain_fast: 4556.500ms

Here is a custom function without regex.

function split(str) {
    let output = []
    let cur = ''
    for(let i = 0; i < str.length; i++) {
        if(str[i] !== '_') {
            output.push(str[i])
            continue;
        }
        
        cur += str[i]
        if(str[i + 1] !== '_') {
             output.push(cur)
             cur = ''
        }
    }
    return output
}

console.log(split('__f__g_f_'))

Related