C# 拆分包含空格的字符串,除非它们包含在“中”;引号;?

C# 拆分包含空格的字符串,除非它们包含在“中”;引号;?,c#,split,C#,Split,让事情变得简单: string streamR = sr.ReadLine(); // sr.Readline results in: // one "two two" 我希望能够将它们保存为两个不同的字符串,删除除引号之间的空格以外的所有空格。因此,我需要的是: string 1 = one string 2 = two two 到目前为止,我发现下面的代码是有效的,但它删除

让事情变得简单:

string streamR = sr.ReadLine();  // sr.Readline results in:
                                 //                         one "two two"
我希望能够将它们保存为两个不同的字符串,删除除引号之间的空格以外的所有空格。因此,我需要的是:

string 1 = one
string 2 = two two
到目前为止,我发现下面的代码是有效的,但它删除了引号中的空格

//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;
这个函数的输出变为

one
two
我已经研究过了,但是我似乎无法让regex工作/理解代码,特别是如何将它们分割成两个不同的字符串。那里的所有代码都给了我一个编译错误(我使用的是
System.Text.RegularExpressions

string input=“一”“二”“二”“三”“四四”“五六”;
var parts=Regex.Matches(输入,@“[\”“]”.+?[\”“].[^]+”)
.Cast()
.选择(m=>m.Value)
.ToList();

因为定制解析器可能更适合这种情况

这是我曾经写过的一篇文章,当时我有一个涉及括号和空格的特定(而且非常奇怪)解析需求,但它足够通用,几乎可以与任何分隔符和文本限定符一起使用

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

    if (line == null)
        yield break;

    else
    {
        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];
            else
                prevChar = '\0';

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

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

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

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

            token = token.Append(currentChar);

        }

        yield return token.ToString();

    } 
}

您甚至可以在不使用正则表达式的情况下实现这一点:使用
String.Split
的LINQ表达式可以完成这项工作

您可以先通过
拆分字符串,然后通过
仅拆分结果数组中索引为偶数的元素

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();
对于字符串:

This is a test for "Splitting a string" that has white spaces, unless they are "enclosed within quotes"
结果如下:

This
is
a
test
for
Splitting a string
that
has
white
spaces,
unless
they
are
enclosed within quotes
更新 更新2 如何定义字符串的引号部分

我们将假定第一个
之前的字符串是非引号

然后,第一个
和第二个
之间的字符串被引用。第二个
和第三个
之间的字符串不带引号。第三个和第四个之间的字符串被引用

一般规则是:引用第(2*n-1)个(奇数)
和第(2*n)个(偶数)
之间的每个字符串<代码>(1)

字符串.Split的关系是什么

使用默认StringSplitOption(定义为StringSplitOption.None)拆分字符串。创建一个包含1个字符串的列表,然后在列表中为找到的每个拆分字符添加一个新字符串

因此,在第一个
之前,字符串位于拆分数组中的索引0处,在第一个
”和第二个
之间,字符串位于数组中的索引1处,在第三个和第四个之间,索引2

一般规则是:第n个和第(n+1)个
之间的字符串位于数组的索引n处。
(2)

对于给定的
(1)
(2)
,我们可以得出结论:引用部分位于拆分数组中的奇数索引处。

您可以使用属于
Microsoft.VisualBasic.FileIO
命名空间的类。(您需要在项目中添加对
Microsoft.VisualBasic
的引用。)

我想

…删除除在引号之间找到的空格以外的所有空格

Cédric Bignon的解决方案几乎做到了这一点,但没有考虑到引号的数量可能不均匀。首先检查引号,然后删除多余的引号,确保只有当元素确实被引号封装时,我们才停止拆分

string myString = "WordOne \"Word Two";
int placement = myString.LastIndexOf("\"", StringComparison.Ordinal);
if (placement >= 0)
myString = myString.Remove(placement, 1);

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();

Console.WriteLine(result[0]);
Console.WriteLine(result[1]);
Console.ReadKey();

这一逻辑归功于塞德里克·比格农,我只添加了一个保护措施。

斯奎兹的回答有一个小问题。.它适用于他的字符串,但如果您添加更多项则不行

string myString = "WordOne \"Word Two\" Three"
在这种情况下,去掉最后一个引号将得到4个结果,而不是3个

这很容易解决。只需计算转义字符的数量,如果不均匀,则去掉最后一个字符(根据您的要求进行调整…)

公共静态列表拆分(此字符串myString、字符分隔符、字符转义字符)
{
int nbescapeCharacters=myString.Count(c=>c==escapeCharacter);
if(nbescapeCharactors%2!=0)//转义字符数不均匀
{
int lastIndex=myString.LastIndexOf(“+escapeCharacter,StringComparison.Ordinal);
myString=myString.Remove(lastIndex,1);//删除最后一个转义字符
}
var result=myString.Split(escapeCharacter)
.选择((元素,索引)=>索引%2==0//如果索引为偶数
?element.Split(新[]{separator},StringSplitOptions.RemoveEmptyEntries)//拆分项
:new string[]{element})//保留整个项目
.SelectMany(element=>element).ToList();
返回结果;
}

我还将其转换为扩展方法,并使分隔符和转义符可配置。

支持双引号

字符串:

a "b b" "c ""c"" c"
结果:

a 
"b b"
"c ""c"" c"
代码:

结果

a 
b b
c "c" c

为此编写自己的解析器可能会更容易-正则表达式不适合这种逻辑。什么编译错误?错误消息是什么?在哪一行?错误1找不到源类型“System.Text.RegularExpressions.MatchCollection”的查询模式的实现。“Cast”找不到。是否缺少对的引用“System.Core.dll”或“System.Linq”的using指令?string.split完美地执行了我想要的,除了我的引号问题这一事实看起来不错,但是有没有办法将列表分割成独立的字符串?(读取行一次只有两个字,包括引号中的字)@Teachme您可以使用just get result[0]和结果[1]。@Teachme你能试试我在我文章的更新部分写的代码吗。你得到了什么结果?我仍然没有跟上你。如果整个字符串都被引用了怎么办?那么只有一个字符串,它位于零的位置,这是偶数。为什么这不是一个I
string myString = "WordOne \"Word Two\" Three"
    public static List<String> Split(this string myString, char separator, char escapeCharacter)
    {
        int nbEscapeCharactoers = myString.Count(c => c == escapeCharacter);
        if (nbEscapeCharactoers % 2 != 0) // uneven number of escape characters
        {
            int lastIndex = myString.LastIndexOf("" + escapeCharacter, StringComparison.Ordinal);
            myString = myString.Remove(lastIndex, 1); // remove the last escape character
        }
        var result = myString.Split(escapeCharacter)
                             .Select((element, index) => index % 2 == 0  // If even index
                                                   ? element.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries)  // Split the item
                                                   : new string[] { element })  // Keep the entire item
                             .SelectMany(element => element).ToList();
        return result;
    }
a "b b" "c ""c"" c"
a 
"b b"
"c ""c"" c"
var list=Regex.Matches(value, @"\""(\""\""|[^\""])+\""|[^ ]+", 
    RegexOptions.ExplicitCapture)
            .Cast<Match>()
            .Select(m => m.Value)
            .ToList();
Select(m => m.StartsWith("\"") ? m.Substring(1, m.Length - 2).Replace("\"\"", "\"") : m)
a 
b b
c "c" c