捕捉模式,但在引号内忽略它

时间:2015-09-26 11:45:16

标签: c# regex

所以,我需要在c#regex中做什么,每当我找到某个模式时,基本上会拆分一个字符串,但如果它被字符串中的双引号包围,则忽略该模式。

示例:

string text = "abc , def , a\" , \"d , oioi";
string pattern = "[ \t]*,[ \t]*";

string[] result = Regex.Split(text, pattern, RegexOptions.ECMAScript);

分割后想要结果(3个分割,4个字符串):

    {"abc",
     "def",
     "a\" , \"d",
     "oioi"}

实际结果(4个分组,5个字符串):

    {"abc",
     "def",
     "a\"",
     "\"d",
     "oioi"}

另一个例子:

string text = "a%2% 6y % \"ad%t6%&\" %(7y) %";
string pattern = "%";

string[] result = Regex.Split(text, pattern, RegexOptions.ECMAScript);

分割后想要结果(5个分割,6个字符串):

    {"a",
     "2",
     " 6y ",
     " \"ad%t6%&\" ",
     "(7y) ",
     ""}

实际结果(7个分组,8个字符串):

    {"a",
     "2",
     " 6y ",
     "\"ad",
     "t6",
     "&\" ",
     "(7y) ",
     ""}

第三个例子,举例说明一个棘手的分裂,其中只应忽略第一种情况:

string text = "!!\"!!\"!!\"";
string pattern = "!!";

string[] result = Regex.Split(text, pattern, RegexOptions.ECMAScript);

分割后想要结果(2个分割,3个字符串):

    {"",
     "\"!!\"",
     "\""}

实际结果(3个分组,4个字符串):

    {"",
     "\"",
     "\"",
     "\"",}

那么,如何从模式转移到实现所需结果的新模式

旁注:如果你要将某人的问题标记为重复(并且我没有反对),至少指出正确的答案,而不是一些随机的帖子(是的,我在看着你,Mr .Avinash Raj)......

2 个答案:

答案 0 :(得分:2)

除了:

之外,规则或多或少类似于csv行
  • 分隔符可以是单个字符,但它也可以是字符串或模式(在这些最后的情况下,如果项目以模式分隔符的最后或第一个可能的标记开始或结束,则必须修剪项目),
  • 最后一项允许使用孤儿引用。

首先,当您想要使用一些高级规则来分隔项目(拆分)时,拆分方法不再是一个好的选择。拆分方法仅适用于简单情况,而不适用于您的情况。 (即使没有孤立引号,使用与,(?=(?:[^"]*"[^"]*")*[^"]*$)分割也是一个非常糟糕的主意,因为解析字符串所需的步骤数会随着字符串大小呈指数级增长。)

另一种方法是捕获物品。这更简单,更快捷。 (奖励:它同时检查整个字符串的格式。)

以下是执行此操作的一般方法:

^
(?>
  (?:delimiter | start_of_the_string)
  (
      simple_part
      (?>
          (?: quotes | delim_first_letter_1 | delim_first_letter_2 | etc. )
          simple_part
      )*
  )
)+
$

\s*,\s*作为分隔符的示例:

^
# non-capturing group for one delimiter and one item
(?>
    (?: \s*,\s* | ^ ) # delimiter or start of the string
                      # (eventually change "^" to "^ \s*" to trim the first item)

    # capture group 1 for the item 
    (   # simple part of the item (maybe empty):
        [^\s,"]* # all that is not the quote character or one of the  possible first
                 # character of the delimiter
        # edge case followed by a simple part
        (?>
            (?: # edge cases
                " [^"]* (?:"|$) # a quoted part or an orphan quote in the last item (*)
              |   # OR
                (?> \s+ ) # start of the delimiter
                (?!,)     # but not the delimiter
            )

            [^\s,"]* # simple part
        )*
    )
)+
$

demo (点击表格链接)

该模式是为Regex.Match方法设计的,因为它描述了所有字符串。所有项目都在组1中可用,因为.net正则表达式风格能够存储重复的捕获组。

这个例子很容易适应所有情况。

(*)如果您想在引用的部分中允许转义引号,则可以再使用一次simple_part (?: edge_case simple_part)* 而不是" [^"]* (?:"|$),即:{ {1}}

答案 1 :(得分:0)

我认为这是一个两步的过程,它已经被推翻,试图让它成为一步正则表达式。

<强>步骤

  1. 只需从字符串中删除任何引号。
  2. 拆分目标角色。
  3. 流程示例

    我会在,上拆分第2步。

    var data = string.Format("abc , def , a{0}, {0}d , oioi", "\"");
    
     // `\x22` is hex for a quote (") which for easier reading in C# editing.
    var stage1 = Regex.Replace(data, @"\x22", string.Empty);
    
    // abc , def , a", "d , oioi
    // becomes
    // abc , def , a, d , oioi
    
    Regex.Matches(stage1, @"([^\s,]+)[\s,]*")
         .OfType<Match>()
         .Select(mt => mt.Groups[1].Value )
    

    <强>结果

    enter image description here