Take the 2-minute tour ×

To make things simple:

string streamR = sr.ReadLine();  // sr.Readline results in one "two two"

I want to be able to save them as two different strings, remove all spaces EXCEPT for the spaces found between quotation marks. Therefore, what I need is:

string 1 = one
string 2 = two two

So far what I have found that works is the following code, but it removes the spaces within the quotes.

//streamR.ReadLine only has two strings
  string[] splitter = streamR.Split(' ');
    str1 = splitter[0];
    // Only set str2 if the length is >1
    str2 = splitter.Length > 1 ? splitter[1] : string.Empty;

The output of this becomes


I have looked into Regular Expression to split on spaces unless in quotes however I can't seem to get regex to work/understand the code, especially how to split them so they are two different strings. All the codes there give me a compiling error (I am using System.Text.RegularExpressions)

share|improve this question
It will probably be easier to write your own parser for this - regex is not suitable for this kind of logic. –  Oded Feb 1 '13 at 21:07
What compiling error? What is the error message? On what line? –  O. R. Mapper Feb 1 '13 at 21:09
Error 1 Could not find an implementation of the query pattern for source type 'System.Text.RegularExpressions.MatchCollection'. 'Cast' not found. Are you missing a reference to 'System.Core.dll' or a using directive for 'System.Linq'? –  Teachme Feb 1 '13 at 21:12
the string.split executes what I want beautifully, besides the fact of my quotation problem –  Teachme Feb 1 '13 at 21:16

4 Answers 4

up vote 11 down vote accepted
string input = "one \"two two\" three \"four four\" five six";
var parts = Regex.Matches(input, @"[\""].+?[\""]|[^ ]+")
                .Select(m => m.Value)
share|improve this answer
Am i missing a using?Error 1 'System.Text.RegularExpressions.MatchCollection' does not contain a definition for 'Cast' and no extension method 'Cast' accepting a first argument of type 'System.Text.RegularExpressions.MatchCollection' could be found –  Teachme Feb 1 '13 at 21:59
@Teachme It requires System.Linq –  I4V Feb 1 '13 at 22:05
this works, but it ignores the fact that white spaces within quotes class it as one token rather than two or more –  Teachme Feb 1 '13 at 22:19
@Teachme I don't understand what you mean. An example maybe? –  I4V Feb 1 '13 at 22:23
Erm, basically if string input ="Apple \"iPhone four\" your code result becomes "Apple", "iPhone", "four". I am trying to get "Apple", "iPhone four" in two different strings so i can store them –  Teachme Feb 1 '13 at 22:36

No need for regex. A simple LINQ expression with String.Split can do the job.

You can split your string before by " then split only the elements with even index in the resulting array by .

var result = myString.Split('"')
                     .Select((element, index) => index % 2 == 0  // If even index
                                           ? element.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)  // Split the item
                                           : new string[] { element })  // Keep the entire item
                     .SelectMany(element => element).ToList();

For the string:

This is a test for "Splitting a string" that has white spaces, unless they are "enclosed within quotes"

It gives the result:

Splitting a string
enclosed within quotes


string myString = "WordOne \"Word Two\"";
var result = myString.Split('"')



How do you define a quoted portion of the string?

We will assume that the string before the first " is non-quoted.

Then, the string placed between the first " and before the second " is quoted. The string between the second " and the third " is non-quoted. The string between the third and the fourth is quoted, ...

The general rule is: Each string between the (2*n-1)th (odd number) " and (2*n)th (even number) " is quoted. (1)

What is the relation with String.Split?

String.Split with the default StringSplitOption (define as StringSplitOption.None) creates an list of 1 string and then add a new string in the list for each splitting character found.

So, before the first ", the string is at index 0 in the splitted array, between the first and second ", the string is at index 1 in the array, between the third and fourth, index 2, ...

The general rule is: The string between the nth and (n+1)th " is at index n in the array. (2)

The given (1) and (2), we can conclude that: Quoted portion are at odd index in the splitted array.

share|improve this answer
That looks good, but is there a way to seperate the list into indidual strings? (the readline will only have two words at a time including those in quotes) –  Teachme Feb 1 '13 at 21:58
@Teachme You can use just get result[0] and result[1]. –  Cédric Bignon Feb 1 '13 at 22:00
@Teachme Can you try the code I've written in the Update section of my post. What result do you have? –  Cédric Bignon Feb 1 '13 at 22:44
I'm still not following you. What if the entire string is quoted? Then there is only one string and it is at position zero, which is even. Why is this not an issue? –  Eric Lippert Feb 2 '13 at 1:24
@EamonNerbonne Exactly, then, the quoted string is still at an odd index in the splitted array. –  Cédric Bignon Feb 2 '13 at 10:16

You can use the TextFieldParser that is part of the Microsoft.VisualBasic.FileIO namespace:

string inputString = "This is \"a test\" of the parser.";

using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(inputString)))
    using (Microsoft.VisualBasic.FileIO.TextFieldParser tfp = new TextFieldParser(ms))
        tfp.Delimiters = new string[] { " " };
        tfp.HasFieldsEnclosedInQuotes = true;
        string[] output = tfp.ReadFields();

        for (int i = 0; i < output.Length; i++)
            Console.WriteLine("{0}:{1}", i, output[i]);

Which generates the output:

2:a test
share|improve this answer
apparently using Microsoft.VisualBasic.FileIO; does not exist in the namespace? –  Teachme Feb 1 '13 at 22:35
Add a reference to Microsoft.VisualBasic to your project. –  John Koerner Feb 3 '13 at 14:50
TextFieldParser implements IDisposable you need to wrap it into "using" or call Close(). –  IT Hit WebDAV Jan 14 at 19:09

As custom parser might be more suitable for this.

This is something I wrote once when I had a specific (and very strange) parsing requirement that involved parenthesis and spaces, but it is generic enough that it should work with virtually any delimiter and text qualifier.

public static IEnumerable<String> ParseText(String line, Char delimiter, Char textQualifier)

    if (line == null)
        yield break;

        Char prevChar = '\0';
        Char nextChar = '\0';
        Char currentChar = '\0';

        Boolean inString = false;

        StringBuilder token = new StringBuilder();

        for (int i = 0; i < line.Length; i++)
            currentChar = line[i];

            if (i > 0)
                prevChar = line[i - 1];
                prevChar = '\0';

            if (i + 1 < line.Length)
                nextChar = line[i + 1];
                nextChar = '\0';

            if (currentChar == textQualifier && (prevChar == '\0' || prevChar == delimiter) && !inString)
                inString = true;

            if (currentChar == textQualifier && (nextChar == '\0' || nextChar == delimiter) && inString)
                inString = false;

            if (currentChar == delimiter && !inString)
                yield return token.ToString();
                token = token.Remove(0, token.Length);

            token = token.Append(currentChar);


        yield return token.ToString();


The usage would be:

var parsedText = ParseText(streamR, ' ', '"');
share|improve this answer

Your Answer


