Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何用正则表达式表示可选组?_C#_Regex - Fatal编程技术网

C# 如何用正则表达式表示可选组?

C# 如何用正则表达式表示可选组?,c#,regex,C#,Regex,我正在尝试使用C#使用正则表达式解析文本 我有以下文本示例1 Fn.If(first condition) When the first condition is valid! This is a required section Fn.ElseIf(some second condition) When the second condition is valid! This is an optional section Fn.ElseIf(third second conditi

我正在尝试使用C#使用正则表达式解析文本

我有以下文本示例1

Fn.If(first condition) 
   When the first condition is valid! This is a required section
Fn.ElseIf(some second condition)
   When the second condition is valid! This is an optional section
Fn.ElseIf(third second condition)
   When the third condition is valid! This is an optional section
Fn.Else
    Catch all! This is an optional section
Fn.End
我希望能够将每个部分提取为3组,以便最终结果如下所示

  • (1A组):如果
  • (1B组):第一条件
  • (1C组):当第一个条件有效时!这是必修课
  • (2A组):Fn.ElseIf
  • (2B组):第二种情况
  • (第2C组):当第二个条件有效时!这是一个可选部分
  • (3A组):Fn.ElseIf
  • (3B组):第三种情况
  • (3C组):当第三个条件有效时!这是一个可选部分
  • (4A组):Fn.其他
  • (4B组):全力以赴!这是一个可选部分
  • (C组):Fn.结束
从注释中可以看到,组1(A/B/C)必须与最后一个组一起存在,模式才能有效。然而,中间的所有组都是可选的,这意味着它们可能存在,也可能不存在

除了上面的文本示例之外,模式还应该能够解析下面的文本示例2

Fn.If(first condition) 
   When first condition is valid! This is a required section
Fn.EndIf
或文本示例3

Fn.If(first condition) 
   When first condition is valid! This is a required section
Fn.Else
    Catch all! This is an optional section
Fn.EndIf
我能做到这一点

  • (Fn\.If.*)\(.+?)\([\s\s]+)(Fn\.EndIf)
    适用于文本示例2
  • (Fn\.ElseIf\s*)\(.+?)\([\s\s]+)
    将返回
    Fn.ElseIf(…)…
  • (Fn\.Else)([\s\s]+)
    将捕获
    Fn.Else….
  • 然而,我正在努力将所有3种模式放在一起,同时设想第2行可以有零个或多个组,然后是第3行中的一个或一个都没有

    我尝试了以下不起作用的方法。为了便于阅读,我在每组后面加了一行,只是为了回答问题

    (Fn\.If\s*)\((.+?)\)([\s\S]+)
    ((Fn\.ElseIf\s*)\((.+?)\)([\s\S]+))*
    ((Fn\.Else)([\s\S]+))?
    (Fn\.EndIf)
    

    我觉得使用单一的单片正则表达式会使事情变得太复杂,所以这里有一个基于有限状态机的方法,仍然使用正则表达式来捕获每一行

    void Main()
    {
        const String input = 
    @"Fn.If(first condition)
       When the first condition is valid! This is a required section
    Fn.ElseIf(some second condition)
       When the second condition is valid! This is an optional section
    Fn.ElseIf(third second condition)
       When the third condition is valid! This is an optional section
    Fn.Else
        Catch all! This is an optional section
    Fn.End  
        ";
    
        Regex rIf     = new Regex( @"^Fn\.If\((.+)\)\s*$" );
        Regex rElseIf = new Regex( @"^Fn\.ElseIf\((.+)\)\s*$" );
        Regex rElse   = new Regex( @"^Fn\.Else\s*$" );
        Regex rEnd    = new Regex( @"^Fn\.End\s*$" );
    
        String[] lines = input.Split(new String[] { "\r\n" }, StringSplitOptions.None );
    
        List<Statement> statements = new List<Statement>();
    
        String type = null;
        String condition = null;
        StringBuilder sb = new StringBuilder();
    
        State state = State.Outside;
        foreach( String line in lines )
        {
            switch( state )
            {
            case State.Outside:
    
                Match mIf = rIf.Match( line );
                if( mIf.Success )
                {
                    type = "Fn.If";
                    condition = mIf.Groups[1].Value;
    
                    state = State.InIf;
                }
    
                break;
            case State.InIf:
            case State.InElseIf:
    
                Match mElseIf = rElseIf.Match( line );
                if( mElseIf.Success )
                {
                    statements.Add( new Statement( type, condition, sb.ToString() ) );
                    sb.Length = 0;
    
                    state = State.InElseIf;
                    type = "Fn.ElseIf";
                    condition = mElseIf.Groups[1].Value;
                }
                else
                {
                    Match mElse = rElse.Match( line );
                    if( mElse.Success )
                    {
                        statements.Add(new Statement(type, condition, sb.ToString()));
                        sb.Length = 0;
    
                        state = State.InElse;
                        type = "Fn.Else";
                        condition = null;
                    }
                    else
                    {
                        sb.Append( line );
                    }
                }
    
                break;
    
            case State.InElse:
    
                Match mEnd = rEnd.Match(line);
                if (mEnd.Success)
                {
                    statements.Add(new Statement(type, condition, sb.ToString()));
                    sb.Length = 0;
    
                    state = State.Outside;
                    type = null;
                    condition = null;
                }
                else
                {
                    sb.Append( line );
                }
    
                break;
            }
        }
    
        statements.Dump();
    }
    
    class Statement
    {
        public Statement( String type, String condition, String contents )
        {
            this.Type = type;
            this.Condition = condition;
            this.Contents = contents;
        }
    
        public String Type { get; }
        public String Condition { get; }
        public String Contents { get; }
    }
    
    // Define other methods and classes here
    enum State
    {
        Outside,
        InIf,
        InElseIf,
        InElse
    }
    
    void Main()
    {
    常量字符串输入=
    @“Fn.如果(第一个条件)
    当第一个条件有效时!这是必需的部分
    Fn.ElseIf(某些第二个条件)
    当第二个条件有效时!这是可选部分
    Fn.ElseIf(第三个第二个条件)
    当第三个条件有效时!这是可选部分
    Fn.其他
    全包!这是一个可选部分
    Fn.完
    ";
    正则表达式rIf=新正则表达式(@“^Fn\。如果“(.+)\)\s*$”;
    正则表达式rElseIf=新正则表达式(@“^Fn\.ElseIf\(.+)\)\s*$”;
    正则表达式rElse=新正则表达式(@“^Fn\.Else\s*$”;
    正则表达式rEnd=新正则表达式(@“^Fn\.End\s*$”;
    String[]lines=input.Split(新字符串[]{“\r\n”},StringSplitOptions.None);
    List语句=新列表();
    字符串类型=null;
    字符串条件=null;
    StringBuilder sb=新的StringBuilder();
    状态=状态。外部;
    foreach(行中的字符串行)
    {
    开关(状态)
    {
    案例状态。外部:
    匹配mIf=重复匹配(行);
    如果(mIf.Success)
    {
    type=“Fn.If”;
    条件=mIf.Groups[1]。值;
    state=state.ini;
    }
    打破
    case State.InIf:
    案例状态.INLESEIF:
    匹配mElseIf=重新匹配(线);
    如果(梅尔塞夫成功)
    {
    Add(新语句(类型、条件、sb.ToString());
    sb.长度=0;
    state=state.InElseIf;
    type=“Fn.ElseIf”;
    条件=mElseIf.Groups[1]。值;
    }
    其他的
    {
    Match mElse=rElse.Match(行);
    如果(成功)
    {
    Add(新语句(类型、条件、sb.ToString());
    sb.长度=0;
    state=state.InElse;
    type=“Fn.Else”;
    条件=空;
    }
    其他的
    {
    某人附加(行);
    }
    }
    打破
    case State.InElse:
    匹配修复=撕裂匹配(线);
    如果(成功)
    {
    Add(新语句(类型、条件、sb.ToString());
    sb.长度=0;
    状态=状态。外部;
    type=null;
    条件=空;
    }
    其他的
    {
    某人附加(行);
    }
    打破
    }
    }
    语句。Dump();
    }
    类语句
    {
    公共语句(字符串类型、字符串条件、字符串内容)
    {
    this.Type=Type;
    这个条件=条件;
    这个.Contents=Contents;
    }
    公共字符串类型{get;}
    公共字符串条件{get;}
    公共字符串内容{get;}
    }
    //在此处定义其他方法和类
    枚举状态
    {
    外面,,
    伊尼夫,
    他自己,
    无意义
    }
    
    在Linqpad中运行会提供以下输出:


    只需一个正则表达式就可以了

    这是正则表达式的python版本,但应该可以翻译成C#

    关键是对所有匹配使用相同的捕获组


    (Fn\.[A-Za-z]+[^\(\n]*)((\(.+?)\)(?你们一定要在这里使用正则表达式吗?就我个人而言,我会使用单独的正则表达式来匹配
    Fn….
    行,并使用
    子字符串捕获文本。我不必使用正则表达式。我想若我有一个逻辑数组会很容易。谢谢你们的回答。我正在尝试应用它,看看它是否能如预期的那个样工作。很简单如果每个命令(if、elseif、else)必须在单独的一行上,那么这些命令可以正常工作。如果它们的命令是一个句子的一部分,情况会怎样呢?例如,
    这是一个Fn.if(1==2)LONG Fn.elseif(2==2)SHORT Fn.else N/a Fn.End sentance,它可能会一直持续下去。
    我该怎么做