/// <summary> /// 使用内部正则表达式初始化 <see cref="AnchorExp"/> 类的新实例。 /// </summary> /// <param name="innerExp">包含的内部正则表达式。</param> internal AnchorExp(Regex innerExp) { ExceptionHelper.CheckArgumentNull(innerExp, "innerExp"); CheckRegex(innerExp); this.innerExp = innerExp; this.BeginningOfLine = false; this.TrailingExpression = null; }
/// <summary> /// 使用要连接的正则表达式初始化 <see cref="ConcatenationExp"/> 类的新实例。 /// </summary> /// <param name="left">要连接的第一个正则表达式。</param> /// <param name="right">要连接的第二个正则表达式。</param> internal ConcatenationExp(Regex left, Regex right) { ExceptionHelper.CheckArgumentNull(left, "left"); ExceptionHelper.CheckArgumentNull(right, "right"); CheckRegex(left); CheckRegex(right); this.left = left; this.right = right; }
/// <summary> /// 使用内部正则表达式初始化 <see cref="AnchorExp"/> 类的新实例。 /// </summary> /// <param name="innerExp">包含的内部正则表达式。</param> internal AnchorExp(Regex innerExp) { if (innerExp == null) { throw CommonExceptions.ArgumentNull("innerExp"); } CheckRegex(innerExp); this.innerExp = innerExp; this.BeginningOfLine = false; this.TrailingExpression = null; }
/// <summary> /// 使用要连接的正则表达式初始化 <see cref="ConcatenationExp"/> 类的新实例。 /// </summary> /// <param name="left">要连接的第一个正则表达式。</param> /// <param name="right">要连接的第二个正则表达式。</param> internal ConcatenationExp(Regex left, Regex right) { if (left == null) { throw CommonExceptions.ArgumentNull("left"); } if (right == null) { throw CommonExceptions.ArgumentNull("right"); } CheckRegex(left); CheckRegex(right); this.left = left; this.right = right; }
/// <summary> /// 检查正则表达式是否可以被嵌套。 /// </summary> /// <param name="regex">要检查的正则表达式。</param> protected static void CheckRegex(Regex regex) { AnchorExp anchor = regex as AnchorExp; if (anchor != null) { if (anchor.BeginningOfLine) { throw CompilerCommonExceptions.NestedBeginningOfLine("regex"); } if (anchor.TrailingExpression == AnchorExp.EndOfLine) { throw CompilerCommonExceptions.NestedEndOfLine("regex"); } throw CompilerCommonExceptions.NestedTrailing("regex"); } if (regex is EndOfFileExp) { throw CompilerCommonExceptions.NestedEndOfFile("regex"); } }
/// <summary> /// 使用内部正则表达式和重复次数初始化 <see cref="RepeatExp"/> 类的新实例。 /// </summary> /// <param name="innerExp">包含的内部正则表达式。</param> /// <param name="minTimes">内部正则表达式的最少重复次数。</param> /// <param name="maxTimes">内部正则表达式的最多重复次数。</param> internal RepeatExp(Regex innerExp, int minTimes, int maxTimes) { if (minTimes < 0) { ExceptionHelper.ArgumentNegative("minTimes"); } if (maxTimes < 0) { ExceptionHelper.ArgumentNegative("maxTimes"); } if (minTimes > maxTimes) { ExceptionHelper.ReversedArgument("minTimes", "maxTimes"); } ExceptionHelper.CheckArgumentNull(innerExp, "innerExp"); CheckRegex(innerExp); this.innerExp = innerExp; this.minTimes = minTimes; this.maxTimes = maxTimes; }
/// <summary> /// 使用内部正则表达式和重复次数初始化 <see cref="RepeatExp"/> 类的新实例。 /// </summary> /// <param name="innerExp">包含的内部正则表达式。</param> /// <param name="minTimes">内部正则表达式的最少重复次数。</param> /// <param name="maxTimes">内部正则表达式的最多重复次数。</param> internal RepeatExp(Regex innerExp, int minTimes, int maxTimes) { if (minTimes < 0) { CommonExceptions.ArgumentNegative("minTimes", minTimes); } if (maxTimes < 0) { CommonExceptions.ArgumentNegative("maxTimes", maxTimes); } if (minTimes > maxTimes) { CommonExceptions.ReversedArgument("minTimes", "maxTimes"); } if (innerExp == null) { throw CommonExceptions.ArgumentNull("innerExp"); } CheckRegex(innerExp); this.innerExp = innerExp; this.minTimes = minTimes; this.maxTimes = maxTimes; }
/// <summary> /// 返回表示可选的正则表达式。 /// </summary> /// <param name="innerExp">可选的内部正则表达式。</param> /// <returns>表示可选的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示可选的正则表达式。 /// </summary> /// </overloads> public static Regex Optional(Regex innerExp) { return new RepeatExp(innerExp, 0, 1); }
/// <summary> /// 返回表示正闭包的正则表达式。 /// </summary> /// <param name="innerExp">正闭包的内部正则表达式。</param> /// <returns>表示正闭包的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示正闭包的正则表达式。 /// </summary> /// </overloads> public static Regex Positive(Regex innerExp) { return new RepeatExp(innerExp, 1, int.MaxValue); }
/// <summary> /// 返回表示 Kleene 闭包的正则表达式。 /// </summary> /// <param name="innerExp">Kleene 闭包的内部正则表达式。</param> /// <returns>表示 Kleene 闭包的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示 Kleene 闭包的正则表达式。 /// </summary> /// </overloads> public static Regex Star(Regex innerExp) { return new RepeatExp(innerExp, 0, int.MaxValue); }
/// <summary> /// 设置当前的正则表达式。 /// </summary> /// <param name="regex">要设置的正则表达式。</param> private void AddRegex(Regex regex) { current = regex; }
/// <summary> /// 返回表示当前正则表达式要向前看指定内容的正则表达式。 /// </summary> /// <param name="regex">要向前看的正则表达式。</param> /// <returns>表示当前正则表达式要向前看指定内容的正则表达式。</returns> public Regex Trailing(Regex regex) { return Trailing(this, regex); }
/// <summary> /// 返回表示两个正则表达式连接的正则表达式。 /// </summary> /// <param name="left">要连接的第一个正则表达式。</param> /// <param name="right">要连接的第二个正则表达式。</param> /// <returns>表示两个正则表达式连接的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示两个正则表达式连接的正则表达式。 /// </summary> /// </overloads> public static Regex Concat(Regex left, Regex right) { return new ConcatenationExp(left, right); }
/// <summary> /// 返回表示至少重复 <paramref name="minTimes"/> 次的正则表达式。 /// </summary> /// <param name="innerExp">重复的的内部正则表达式。</param> /// <param name="minTimes">最少的重复次数。</param> /// <returns>表示至少重复 <paramref name="minTimes"/> 次的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示至少重复 <paramref name="minTimes"/> 次的正则表达式。 /// </summary> /// </overloads> public static Regex RepeatMinTimes(Regex innerExp, int minTimes) { return new RepeatExp(innerExp, minTimes, int.MaxValue); }
/// <summary> /// 结束当前的正则表达式单元(找到数量词)。 /// </summary> /// <param name="min">最小重复次数。</param> /// <param name="max">最大重复次数。</param> private void AddConcatenate(int min, int max) { Debug.Assert(current != null); concatenate.Add(current.Repeat(min, max)); current = null; }
/// <summary> /// 设置当前的正则表达式为一个单独的字符。 /// </summary> /// <param name="ch">正则表达式包含的字符。</param> private void AddSymbol(char ch) { if (UseOptionIgnoreCase) { current = Regex.SymbolIgnoreCase(ch, culture); } else { current = Regex.Symbol(ch); } }
private Regex ScanRegex() { // 是否需要读取向前看符号。 bool readTrailing = false; // 非特殊的字符,标识开始。 int ich = '@'; // 是否是数量词。 bool isQuantifier = false; while (!EndOfPattern) { bool wasPrevQuantifier = isQuantifier; isQuantifier = false; ScanBlank(); string normalChars = ScanNormalChars(); ScanBlank(); if (EndOfPattern) { // 非特殊的字符,表示结束。 ich = '!'; } else if (IsSpecial(ich = reader.Peek())) { isQuantifier = IsQuantifier(ich); // 排除 {name} 情况。 if (isQuantifier && ich == '{' && !IsTrueQuantifier()) { isQuantifier = false; } reader.Read(); } else { // 非特殊的字符,表示普通的字符。 ich = ' '; } if (normalChars.Length > 0) { wasPrevQuantifier = false; // 如果之后是量词的话,量词只针对最后一个字符。 if (isQuantifier) { if (normalChars.Length > 1) { AddLiteral(normalChars.Substring(0, normalChars.Length - 1)); } AddSymbol(normalChars[normalChars.Length - 1]); } else { AddLiteral(normalChars); } } switch (ich) { case '!': goto BreakOuterScan; case ' ': goto ContinueOuterScan; case '[': AddCharClass(ScanCharClass(true).ToStringClass()); break; case '(': PushOptions(); if (ScanGroupOpen()) { PushGroup(); } else { PopKeepOptions(); } continue; case '|': AddAlternate(); goto ContinueOuterScan; case ')': if (EmptyStack) { ThrowTooManyParens(); } AddGroup(); PopGroup(); if (current == null) { goto ContinueOuterScan; } break; case '\\': AddRegex(ScanBackslash()); break; case '/': if (inTrailing) { ThrowNestedTrailing(); } readTrailing = true; goto BreakOuterScan; case '$': // $ 仅在结尾表示行结尾,否则表示普通的符号。 // 在 Trailing 中,最后的 $ 不再认为是行结束符。 if (EndOfPattern && !inTrailing) { trailing = AnchorExp.EndOfLine; goto BreakOuterScan; } else { AddSymbol('$'); } break; case '.': AddRegex(Regex.AnyChar(UseOptionSingleLine)); break; case '{': case '*': case '+': case '?': if (current == null) { if (ich == '{') { // {regexName} 情况。 reader.Drop(); SourcePosition start = reader.StartPosition; string name = ScanCapname(); SourcePosition end = reader.StartPosition; if (reader.Read() == '}') { if (!regexDefinition.TryGetValue(name, out current)) { ThrowUndefinedRegex(name, start, end); } break; } else { ThrowIncompleteRegexReference(); } } else if (wasPrevQuantifier) { ThrowNestedQuantify(((char)ich).ToString()); } else { ThrowQuantifyAfterNothing(); } } reader.Unget(); break; case '"': // 字符串。 string str = ScanLiteral(); if (UseOptionIgnoreCase) { AddRegex(Regex.LiteralIgnoreCase(str, culture)); } else { AddRegex(Regex.Literal(str)); } break; default: Debug.Fail("内部的 ScanRegex 错误"); break; } ScanBlank(); if (EndOfPattern || !(isQuantifier = IsTrueQuantifier())) { AddConcatenate(); goto ContinueOuterScan; } ScanRepeat(); ContinueOuterScan: ; } BreakOuterScan: if (!EmptyStack) { ThrowNotEnoughParens(); } AddGroup(); Regex tempRegex = current; current = null; if (readTrailing) { inTrailing = true; trailing = ScanRegex(); inTrailing = false; } if (trailing != null) { tempRegex = tempRegex.Trailing(trailing); } return tempRegex; }
/// <summary> /// 结束当前的组(例如 ) 或到达模式结尾)。 /// </summary> private void AddGroup() { AddAlternate(); int cnt = alternation.Count; if (cnt > 0) { Regex regex = alternation[0]; for (int i = 1; i < cnt; i++) { regex = regex.Union(alternation[i]); } alternation.Clear(); current = regex; } else { current = null; } }
/// <summary> /// 返回表示重复多次的正则表达式。 /// </summary> /// <param name="innerExp">重复的的内部正则表达式。</param> /// <param name="times">重复次数。</param> /// <returns>表示重复多次的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示重复多次的正则表达式。 /// </summary> /// </overloads> public static Regex Repeat(Regex innerExp, int times) { return new RepeatExp(innerExp, times, times); }
/// <summary> /// 返回表示行的起始位置的正则表达式。 /// </summary> /// <param name="innerExp">内部的正则表达式。</param> /// <returns>表示行的起始位置的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示行的起始位置的正则表达式。 /// </summary> /// </overloads> public static Regex BeginningOfLine(Regex innerExp) { AnchorExp anchorExp = innerExp as AnchorExp; if (anchorExp == null) { anchorExp = new AnchorExp(innerExp); } anchorExp.BeginningOfLine = true; return anchorExp; }
/// <summary> /// 返回表示重复多次的正则表达式。 /// </summary> /// <param name="innerExp">重复的的内部正则表达式。</param> /// <param name="minTimes">最少的重复次数。</param> /// <param name="maxTimes">最多的重复次数。</param> /// <returns>表示重复多次的正则表达式。</returns> public static Regex Repeat(Regex innerExp, int minTimes, int maxTimes) { return new RepeatExp(innerExp, minTimes, maxTimes); }
/// <summary> /// 返回表示当前正则表达式与指定的正则表达式并联的正则表达式。 /// </summary> /// <param name="right">要并联的个正则表达式。</param> /// <returns>表示两个正则表达式并联的正则表达式。</returns> public Regex Union(Regex right) { return Union(this, right); }
/// <summary> /// 返回表示至多重复 <paramref name="maxTimes"/> 次的正则表达式。 /// </summary> /// <param name="innerExp">重复的的内部正则表达式。</param> /// <param name="maxTimes">最多的重复次数。</param> /// <returns>表示至多重复 <paramref name="maxTimes"/> 次的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示至多重复 <paramref name="maxTimes"/> 次的正则表达式。 /// </summary> /// </overloads> public static Regex RepeatMaxTimes(Regex innerExp, int maxTimes) { return new RepeatExp(innerExp, 0, maxTimes); }
/// <summary> /// 结束当前的正则表达式单元(没有找到数量词)。 /// </summary> private void AddConcatenate() { if (current != null) { concatenate.Add(current); current = null; } }
/// <summary> /// 返回表示两个正则表达式并联的正则表达式。 /// </summary> /// <param name="left">要并联的第一个正则表达式。</param> /// <param name="right">要并联的第二个正则表达式。</param> /// <returns>表示两个正则表达式并联的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示两个正则表达式并联的正则表达式。 /// </summary> /// </overloads> public static Regex Union(Regex left, Regex right) { return new AlternationExp(left, right); }
/// <summary> /// 返回表示向前看的正则表达式。 /// </summary> /// <param name="innerExp">内部的正则表达式。</param> /// <param name="regex">要向前看的正则表达式。</param> /// <returns>表示向前看的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示向前看的正则表达式。 /// </summary> /// </overloads> public static Regex Trailing(Regex innerExp, Regex regex) { AnchorExp anchorExp = innerExp as AnchorExp; if (anchorExp == null) { anchorExp = new AnchorExp(innerExp); } anchorExp.TrailingExpression = regex; return anchorExp; }
/// <summary> /// 返回表示当前正则表达式与指定的正则表达式连接的正则表达式。 /// </summary> /// <param name="right">要连接的正则表达式。</param> /// <returns>表示两个正则表达式连接的正则表达式。</returns> public Regex Concat(Regex right) { return Concat(this, right); }
/// <summary> /// 设置当前的正则表达式为一个字符类。 /// </summary> /// <param name="cc">正则表达式包含的字符类。</param> private void AddCharClass(string cc) { current = Regex.CharClass(cc); }
/// <summary> /// 返回表示当前正则表达式与指定的正则表达式并联的正则表达式。 /// </summary> /// <param name="right">要并联的个正则表达式。</param> /// <returns>表示两个正则表达式并联的正则表达式。</returns> public Regex BitwiseOr(Regex right) { return Union(this, right); }
/// <summary> /// 返回表示行的结束位置的正则表达式。 /// </summary> /// <param name="innerExp">内部的正则表达式。</param> /// <returns>表示行的结束位置的正则表达式。</returns> /// <overloads> /// <summary> /// 返回表示行的结束位置的正则表达式。 /// </summary> /// </overloads> public static Regex EndOfLine(Regex innerExp) { return Trailing(innerExp, AnchorExp.EndOfLine); }