Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a string like

 "asdf a  b c2 "

And I want to split it into an array like this:

["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

Using string.split(" ") removes the spaces, resulting in this:

["asdf", "a", "", "b", "c2"]

I thought of inserting extra delimiters, e.g.

string.replace(/ /g, "| |").replace(/||/g, "|").split("|");

But this gives an unexpected result.

share|improve this question
    
Seems to be a duplicate of stackoverflow.com/questions/4514144/… –  Curious yesterday
    
@Curious Does seem similar, though highest voted answer there gives an odd result with 'asdf a b. . c2% * '. –  Jack yesterday
    
Frankly, i'd rather close the old one as a duplicate of this one. The accepted answer here is more correct. –  cHao yesterday
    
add comment

5 Answers

up vote 10 down vote accepted

Instead of splitting, it might be easier to think of this as extracting strings comprising either the delimiter or consecutive characters that are not the delimiter:

'asdf a  b c2 '.match(/\S+|\s/g)
// result: ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]
'asdf a  b. . c2% * '.match(/\S+|\s/g)
// result: ["asdf", " ", "a", " ", " ", "b.", " ", ".", " ", "c2%", " ", "*", " "]

A more Shakespearean definition of the matches would be:

'asdf a  b c2 '.match(/ |[^ ]+/g)

To or (not to )+.

share|improve this answer
    
@Jack Thanks! This gives the output I want in the example case, but other characters get stripped.. –  gandalf3 yesterday
    
@gandalf3 I don't know what you mean by "other characters". Could you give a concrete example? –  Jack yesterday
1  
@gandalf3 \S is the opposite of \s .. it could also be written as [^\s]. –  Jack yesterday
1  
Nice :) I got my mind stuck on split... :P +1 –  Amadan yesterday
2  
+1 for Shakespearean definition –  Tibos yesterday
show 4 more comments

Use positive lookahead:

"asdf a  b c2 ".split(/(?= )/)
// => ["asdf", " a", " ", " b", " c2", " "]

Post-edit EDIT: As I said in comments, the lack of lookbehind makes this a bit trickier. If all the words only consist of letters, you can fake lookbehind using \b word boundary matcher:

"asdf a  b c2 ".split(/(?= )|\b/)
// => ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

but as soon as you get some punctuation in, it breaks down, since it does not only break on spaces:

"asdf-eif.b".split(/(?= )|\b/)
// => ["asdf", "-", "eif", ".", "b"]

If you do have non-letters you don't want to break on, then I will also suggest a postprocessing method.

Post-think EDIT: This is based on JamesA's original idea, but refined to not use jQuery, and to correctly split:

function chop(str) {
  var result = [];
  var pastFirst = false;
  str.split(' ').forEach(function(x) {
    if (pastFirst) result.push(' ');
    if (x.length) result.push(x);
    pastFirst = true;
  });
  return result;
}
chop("asdf a  b c2 ")
// => ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]
share|improve this answer
    
This works great for what I wrote in my question, but I just realized I made a mistake with the examples.. See my edited question. –  gandalf3 yesterday
    
@gandalf3 you want them not as strings? –  limelights yesterday
    
@limelights I want each space to be in a single element. There should never be a space + anything else in one element. –  gandalf3 yesterday
1  
@limelights: Originally the split was before each space; now it is before and after each space. Unfortunately, JavaScript does not have lookbehind, so this is a bit harder... –  Amadan yesterday
    
Thanks! This works great, but accepted Jack's answer because it's shorter (though that solution does split on any whitespace character, not just spaces. But it's fine for my case). I would accept both if I could.. (+1 btw) –  gandalf3 yesterday
add comment

You could use a little jQuery

var toSplit = "asdf a  b c2 ".split(" ");
$.each(toSplit, 
    function(index, value) { 
        if (toSplit[index] == '') { toSplit[index] = ' '} 
    }
);

This will create the output you are looking for without the leading spaces on the other elements.

share|improve this answer
2  
No need for jQuery in newer environments - jQuery.each is a poor man's [].foreach. –  Amadan yesterday
add comment

"asdf a b c2 ".split(' ').join(' ,');

share|improve this answer
    
This returned a,s,d,f,,,a, , ,b, ,c,2 for me.. –  gandalf3 yesterday
    
make sure to give space in first param of replace method –  user3004406 yesterday
    
I just double checked, there is a space there. It still gives the same output.. –  gandalf3 yesterday
    
This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post. –  Florian F. yesterday
    
Hey i am sorry buddy i thought you are trying in java.Check i post jquery code now –  user3004406 yesterday
show 2 more comments

I'm surprised no one has mentioned this yet, but I'll post this here for the sake of completeness. If you have capturing groups in your expression, then .split will include the captured substring as a separate entry in the result array:

"asdf a  b c2 ".split(/( )/)  // or /(\s)/
// ["asdf", " ", "a", " ", "", " ", "b", " ", "c2", " ", ""]

Note, this is not exactly the same as the desired output you specified, as it includes an empty string between the two contiguous spaces and after the last space.

If necessary, you can filter out all empty strings from the result array like this:

"asdf a  b c2 ".split(/( )/).filter(String)
// ["asdf", " ", "a", " ", " ", "b", " ", "c2", " "]

However, if this is what you're looking for, I'd probably recommend you go with @Jack's solution.

share|improve this answer
    
Oops, sorry.. The empty string at the end was the typo. I've edited my question. –  gandalf3 yesterday
    
@gandalf3 Okay, I've included an alternate solution that will get you the desired result in that case. –  p.s.w.g yesterday
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.