首页 > 解决方案 > 如何只拆分最外层

问题描述

我有一个这样的语句字符串:

    *
    | { table_name | view_name | table_alias }.*
    | {
        [ { table_name | view_name | table_alias }. ]
        { column_name | $IDENTITY | $ROWGUID }
        | udt_column_name [ { . | :: } { { property_name | field_name } | method_name ( argument [ ,...n] ) } ]
        | expression
        [ [ AS ] column_alias ]
      }
    | column_alias = expression 

我只需要最外面的项目,所以我使用 char|来分割内容,我想排除|括号中的任何存在。
拆分的结果是它有 4 个项目,如下所示:

#1 *
#2 { table_name | view_name | table_alias }.*
#3{ [ { table_name | view_name | table_alias }. ] { column_name | $IDENTITY | $ROWGUID } | udt_column_name [ { . | :: } { { property_name | field_name } | method_name ( argument [ ,...n] ) } ] | expression [ [ AS ] column_alias ] }

#4column_alias = expression

我尝试了一些类似(?m)\s*^\|\s*^(({\|\s*})({\{})?)({.+})$但只给我一件而不是四件的东西。
感谢@Wiktor Stribiżew 和@Rui Jarimba 的帮助。

我有想法(?<!\{[^\}]*)\|(?![^\{]*\}),我得到这样的:

#1 *
#2 { table_name | view_name | table_alias }.*
#3

 {
                [ { table_name | view_name | table_alias }. ]
                { column_name | $IDENTITY | $ROWGUID }

#4

udt_column_name [ { . | :: } { { property_name | field_name } | method_name ( argument [ ,...n] ) } ]
                    | expression
                    [ [ AS ] column_alias ]
                  }

#5column_alias = expression

现在,我需要进行一些更改来修复(?<!\{[^\}]*)\|(?![^\{]*\})和清除 #4 ....

好的,我找到了一个模式,可能它并不完美,但它是有效的。它是这样的:

Regex.Split(s, @"(?<!\{(?>[^\{\}]+|\{(?<D>)|\}(?<-D>))*(?(D)(?!)))\|(?!(?>[^\{\}]+|\{(?<D>)|\}(?<-D>))*(?(D)(?!))\})")

最后,我要感谢所有再次帮助我的人。

标签: c#regexsplit

解决方案


它是这样的:

using System.Text.RegularExpressions;

static void Main(string[] args)
{
    string text = @"*
    | { table_name | view_name | table_alias }.*
    | {
        [ { table_name | view_name | table_alias }. ]
        { column_name | $IDENTITY | $ROWGUID }
        | udt_column_name [ { . | :: } { { property_name | field_name } | method_name ( argument [ ,...n] ) } ]
        | expression
        [ [ AS ] column_alias ]
    }
    | column_alias = expression";


    string pattern = BuildPattern();
    RegexOptions options = RegexOptions.Compiled | RegexOptions.Multiline;


    // solution 1: using a MatchEvaluator(Match) delegate
    string normalizedText = Regex.Replace(text, pattern, GetNormalizedLine, options);

    // solution 2: using replacement groups
    string normalizedText2 = Regex.Replace(text, pattern, "$3$4", options);

    bool areEqual = normalizedText2.Equals(normalizedText);

    Console.Read();
}

private static string BuildPattern()
{
    // '|' is special character, needs to be escaped. 
    // Assuming there might be some whitespace after the pipe
    string pipe = @"\|\s*";

    // '{' is special character, needs to be escaped. 
    string bracket = @"\{";

    // remaining text in the line
    string otherText = @".+";

    // using parenthesis () to group the results
    string pattern = $"^(({pipe})({bracket})?)({otherText})$";

    return pattern;
}

private static string GetNormalizedLine(Match match)
{
    GroupCollection groups = match.Groups;

    return $"{groups[3].Value}{groups[4].Value}";
}

输出是以下字符串:

*
{ table_name | view_name | table_alias }.*
{
    [ { table_name | view_name | table_alias }. ]
    { column_name | $IDENTITY | $ROWGUID }
    | udt_column_name [ { . | :: } { { property_name | field_name } | method_name ( argument [ ,...n] ) } ]
    | expression
    [ [ AS ] column_alias ]
  }
column_alias = expression

编辑

正如 OP 所提到的,我没有使用 Regex.Split(),因为我认为没有必要删除该|字符。要获得包含所有行(不包括空格)的数组很简单:

string[] lines = normalizedText.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);

一些注意事项:

  • 我假设要删除的字符始终位于行首,即该字符之前|没有空格
  • 我假设字符和字符之间可能有一些空格|{
  • 我正在使用括号对匹配项进行分组(请参阅C# 中的正则表达式组

推荐阅读