2015-09-26 21 views
1

所以,我在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串):

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

那么,我该怎么办从模式移动到一个新的模式,实现所需的结果?如果你打算把某人的问题标记为重复(并且我没有任何反对意见),至少将它们指向正确的答案,而不是一些随机的帖子(是的,我在看着你,阿维纳什拉吉先生)...

+0

您是否删除了以前的曲estion? –

+1

您已重新发布与[this one](http://stackoverflow.com/q/3147836/335858)的副本相同的问题。如果你认为你的问题是**而不是**这个问题的重复,请在问题的正文中解释它。 – dasblinkenlight

+0

@AvinashRaj [是的,他确实](http://stackoverflow.com/q/32796029/335858)。 – dasblinkenlight

回答

2

的规则是一个CSV行或多或少的相似,不同的:

  • 分隔符可以是单个字符,但它可以是一个字符串或过于模式(在这些最后的情况下,如果项目以模式分隔符的最后或第一个可能的标记开始或结束,则必须将其修剪),
  • or orpha最后一项允许报价。

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

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

这里是做一般的方式:

^ 
(?> 
    (?: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方法设计。由于.net正则表达式可以存储重复的捕获组,因此所有项目都可在组1中使用。

这个例子可以很容易地适用于所有情况。

(*)如果你想允许引用内部零件转义引号,你可以用更多的时间simple_part (?: edge_case simple_part)*而不是" [^"]* (?:"|$)
即:"[^\\"]* (?: \\. [^\\"]*)* (?:"|$)

0

我觉得这是一个两步的过程,它具有试图使它成为一步式正则表达式。


步骤

  1. 只需从一个字符串中删除的任何报价。
  2. 分割目标角色。

处理的实例

我将在,拆分步骤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