Cutting a string at nth occurrence of a character

61,953

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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;

Solution 5

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;
}
Share:
61,953
Anonymous
Author by

Anonymous

Updated on August 22, 2021

Comments

  • Anonymous
    Anonymous over 2 years

    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.

    • tvanfosson
      tvanfosson about 13 years
      Any objection to splitting into an array, then joining slices of the arrays back together? It uses functions that either operate on strings or produce strings.
    • Tejs
      Tejs about 13 years
      It seems you already know the answer; splitting the string on your separator and then reforming a new string with the parts seems the best option. Why limit yourself to not using an array?
    • Anonymous
      Anonymous about 13 years
      I wasn't specific enough. I don't want to make an extra array in addition to the string. Using array functions on the string works for what I'm trying to achieve. I'll fix the question.
    • user3167101
      user3167101 about 13 years
      @tvanfosson Why is my answer wrong?
    • user3167101
      user3167101 about 13 years
      @tvanfosson I believe we may have interpreted the OP's question differently.
    • tvanfosson
      tvanfosson about 13 years
      @alex - I see. I took the example as the specific instance of n that he was interested in. You took it as for any given n produce a result and selected a different value for n. Seems reasonable. I withdraw my objection and delete my comment.
  • tvanfosson
    tvanfosson about 13 years
    I thought the result was supposed to be both "this.those" and "that"?
  • user3167101
    user3167101 about 13 years
    @tvanfosson Maybe I misinterpreted the question, but it was accepted :)
  • iamserious
    iamserious over 12 years
    I wish there was a way to favourite just this answer!
  • Dan Smart
    Dan Smart over 8 years
    To get "this.those" and "that", change slice(start) to slice(0,start)
  • killua8p
    killua8p over 8 years
    This one is better than the accepted answer. Sometimes the delimiter could be a regex (e.g. \s+). In such case, the accepted answer won't work. But this one will.
  • hooke
    hooke over 8 years
    @dan-smart To get both parts, "this" and "those.that", one has to take both slices, see below
  • Daniël Teunkens
    Daniël Teunkens about 8 years
    Even shorter by using the optional limit parameter in split: result = str.split(delimiter, start+1).join(delimiter)
  • user3167101
    user3167101 about 8 years
    @DaniëlTeunkens Nice, I never realised split() could take a second argument. I can change the answer to suit.
  • user3167101
    user3167101 about 8 years
    @killua8p Odd reasoning. If sometimes the delimiter could be a regex you would design it as such. If it was to split on a string, you shouldn't always favour regex because you may need it. YAGNI.
  • user3167101
    user3167101 about 8 years
    @DaniëlTeunkens It looks like the limit argument lets you stop splitting after so many matches, but in this case it wouldn't work because we want something like a negative limit, i.e. stop when splitting from right to left.
  • jazzgil
    jazzgil almost 7 years
    This one about 4 times faster.