使用空格和引号解析字符串(保留引号)

时间:2016-01-05 08:20:57

标签: c# regex string

如果我有string这样的话

create myclass "56, 'for the better or worse', 54.781"

我如何解析它,结果将是三个字符串“单词”,其中包含以下内容:

[0] create
[1] myclass
[2] "56, 'for the better or worse', 54.781"

编辑2:请注意要保留引号

起初,我尝试使用string.Split(' '),但我注意到它会使第三个string被破坏为其他几个字符串。

我尝试使用Split参数count来限制3结果来解决此问题。对于这种情况是否可以,但是当给定的字符串是

create myclass false "56, 'for the better or worse', 54.781" //or
create myclass "56, 'for the better or worse', 54.781" false

然后拆分失败,因为最后两个单词将合并。

我还创建了ReadInBetweenSameDepth之类的内容,以便在引号之间加上string

这是我的ReadInBetweenSameDepth方法

//Examples:
    //[1] (2 + 1) * (5 + 6) will return 2 + 1
    //[2] (2 * (5 + 6) + 1) will return 2 * (5 + 6) + 1
public static string ReadInBetweenSameDepth(string str, char delimiterStart, char delimiterEnd) {
  if (delimiterStart == delimiterEnd || string.IsNullOrWhiteSpace(str) || str.Length <= 2)
    return null;
  int delimiterStartFound = 0;
  int delimiterEndFound = 0;
  int posStart = -1;
  for (int i = 0; i < str.Length; ++i) {
    if (str[i] == delimiterStart) {
      if (i >= str.Length - 2) //delimiter start is found in any of the last two characters
        return null; //it means, there isn't anything in between the two
      if (delimiterStartFound == 0) //first time
        posStart = i + 1; //assign the starting position only the first time...
      delimiterStartFound++; //increase the number of delimiter start count to get the same depth
    }
    if (str[i] == delimiterEnd) {
      delimiterEndFound++;
      if (delimiterStartFound == delimiterEndFound && i - posStart > 0)
        return str.Substring(posStart, i - posStart); //only successful if both delimiters are found in the same depth
    }
  }
  return null;
}

但是虽然这个函数正常工作,但我发现很难将结果与string.Split结合起来,以便根据需要进行正确的解析。

编辑2:在我糟糕的解决方案中,我需要稍后重新添加引号

有没有更好的方法呢?如果我们使用Regex,我们该如何做?

编辑:

老实说,我不知道这个问题可以像CSV格式的文本一样解决。我也不知道这个问题不一定由Regex解决(因此我将其标记为这样)。我真诚地向那些认为这是重复帖子的人道歉。

编辑2:

在对我的项目进行更多工作之后,我意识到我的问题出了问题(也就是说,我没有包含引号) - 我向以前最好的回答者Tim Schmelter先生道歉。然后在查看了欺骗链接之后,我注意到它也没有为此提供答案。

3 个答案:

答案 0 :(得分:3)

您可以按此分割

\s(?=(?:[^"]*"[^"]*")*[^"]*$)

参见演示。

https://regex101.com/r/fM9lY3/60

string strRegex = @"\s(?=(?:[^""]*""[^""]*"")*[^""]*$)";
Regex myRegex = new Regex(strRegex, RegexOptions.Multiline);
string strTargetString = @"create myclass ""56, 'for the better or worse', 54.781""";

return myRegex.Split(strTargetString);

答案 1 :(得分:2)

Regex Demo

(\w+|"[^"]*")

在第一个捕获组中获取匹配项。

  1. \w+:匹配字母数字字符并下划一次或多次
  2. "[^"]*":匹配用双引号
  3. 包装的所有内容
  4. |:正则表达式中的OR条件

答案 2 :(得分:1)

我会使用真正的csv-parser来完成这项任务。框架中唯一可用的是VisualBasic命名空间中的TextFieldParser-class

string str = "create myclass \"56, 'for the better or worse', 54.781\"";
var allLineFields = new List<string[]>();
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(new StringReader(str)))
{
    parser.Delimiters = new string[] { " " };
    parser.HasFieldsEnclosedInQuotes = true;  // important
    string[] lineFields;
    while ((lineFields = parser.ReadFields()) != null)
    {
        allLineFields.Add(lineFields);
    }
}

结果:

enter image description here

但还有其他可用的内容,例如thisthis