C#Regex.Split - 想用char分割字符串,但允许在'和'之间使用char

时间:2010-11-30 08:19:39

标签: c# regex

我想按/分割字符串,但也允许''之间的任何内容包含我的分割字符。从分割中移除''以及任何空白。

示例/'TEST/:1'/3分为

  • Test/:1
  • 3

我有一些接近的东西:

regex.split(test, "/(?=(?:[^']*'[^']*')*[^']*$)" 

但它仍然有'和空白。

string[] fields = Regex.Split(Path, "/(?=(?:[^']*'[^']*')*[^']*$)");

对不起我很清楚它我自己的路径格式解析EDI就像文件一样工作。 /Location:LineNumber/YPosition。我想要做的就是进入命令行/TEST:4/6 = /Location(Test):LineNumber(4)/YPosition(6)。但我的问题是,我的代码确定了位置,可能是第一个分隔符。它可以是日期格式12/03/03,它在EDI类型文件中很常见。

我希望能够让我的命令看起来像这样/'12/03/03':4/6,这样当我的regex.split拆分位置时,它不会在('和')位置之间包含任何内容。

请帮忙吗?

3 个答案:

答案 0 :(得分:1)

你真正想要实现的目标并不完全清楚。如果要解析类似CSV的文件格式,最好使用CSV解析器;如果要操作文件路径,则使用标准库的路径操作函数。与简单的正则表达式相比,两者都能更好地处理边缘情况。

那就是说,你可以做到

MatchCollection allMatchResults = null;
Regex regexObj = new Regex(
    @" "" [^""]* ""  # either match a (double-)quoted string
    |                # or
    [^/\s]*          # a sequence of characters other than / or whitespace", 
    RegexOptions.IgnorePatternWhitespace);
allMatchResults = regexObj.Matches(subjectString);

这不会处理带引号的字符串中的转义引号,但如果输入中没有引号,则它应该有效。

请注意,"Test / 1"/1/2 3/45将分为"Test / 1"12345,因为空白会被删除,因此作为分隔符。

答案 1 :(得分:1)

class Program
    {
        static void Main(string[] args)
        {
            string input = "\"\"/one/\"two/threefour\"/five//";

            var separator = "/";

            var empty = "(?<empty>\\s*)";

            var word = string.Format("(?<word>[^{0}]+)",  separator);
            var quotedWord = "(?<word>[^\\\"]+)";

            var token = string.Format("((\"({0}|{1})\")|({0}|{2}))",empty, quotedWord, word);

            var pattern = string.Format("({0}/)+({0})", token);

            foreach (var capture in Regex.Match(input, pattern).Groups["word"].Captures)
                Console.WriteLine(capture);

        }


    }

答案 2 :(得分:1)

Split并非真正适合此类工作的工具。如果你只是在斜杠上拆分它会很好,但是通过添加可选引号,匹配字段而不是分隔符变得更容易。这是一个允许单引号或双引号字符串的正则表达式,并将/:和空格视为分隔符:

  Regex r1 = new Regex(@"
      ""(?<FIELD>[^""]*)""
      |
      '(?<FIELD>[^']*)'
      |
      (?<FIELD>[^""'/:\s]+)
  ", RegexOptions.IgnorePatternWhitespace);

  string[] source = { @"/TEST:4/6", @"/'12/03/03':4/6" };
  foreach (string s in source)
  {
    foreach (Match m in r1.Matches(s))
    {
      Console.WriteLine(m.Groups["FIELD"].Value);
    }
    Console.WriteLine();
  }

输出:

TEST
4
6

12/03/03
4
6

如果字段中包含引号,则重新使用FIELD组名称可以轻松删除引号。这是一种更“语义”的方法,它在一次传递中匹配整个字符串,并使用命名组来对字段值进行归类。我只是将它们插入到替换字符串中,但您可以使用Groups方法访问它们,就像我在第一个示例中所做的那样。

  Regex r2 = new Regex(@"
      / \s*
        (?:
           (?<Q>[""'])(?<LOC>(?:(?!\<Q>).)*)\1
         |
           (?<LOC>[^""'/:]+)
        ) \s*
      : \s* (?<LINE>\d+) \s*
      / \s* (?<YPOS>\d+)
    ", RegexOptions.IgnorePatternWhitespace);

  foreach (string s in source)
  {
    Console.WriteLine(r2.Replace(s,
        @"Location(${LOC}):LineNumber(${LINE})/YPosition(${YPOS})")
    );
    Console.WriteLine();
  }

输出:

Location(TEST):LineNumber(4)/YPosition(6)

Location(12/03/03):LineNumber(4)/YPosition(6)

此正则表达式不会将空格视为分隔符,但它允许在字段值周围填充空格。它还将单引号和双引号字段与相同的构造进行匹配。在这种情况下,这并不值得额外的复杂性,但这是一种值得了解的技术。