3

我需要解析这样的字符串:

text0<%code0%>text1<%code1%><%%>text3

分成两个数组。每个块都是可选的,因此它可以只是textor<%code%>或空字符串。取出代码很容易(如果我没记错的话):,<%(.*?)%>但我需要文本帮助,因为它没有这样的标记,不像代码。

谢谢!

4

4 回答 4

4

由于正则表达式匹配必须是连续的(即没有间隙),因此没有单个表达式可以匹配标签之外的所有文本。但是,如果您将正则表达式与 C# 的string工具结合使用,您仍然可以这样做,如下所示:

var outside = string.Join("", Regex.Split(inputString, "<%.*?%>"));

如果标签内部可能不包含百分比字符,您可以优化您的正则表达式以避免回溯,而是使用以下表达式:

<%[^%]*%>
于 2013-08-05T10:29:12.400 回答
1

这个非常简单的正则表达式就可以了 :-) :-) (这很讽刺......正则表达式是正确的,但它绝对不可读,即使是正则表达式专家也可能需要至少 10 分钟才能完全理解它)

var rx = new Regex("((?<1>((?!<%).)+)|<%(?<2>((?!%>).)*)%>)*", RegexOptions.ExplicitCapture);
var res2 = rx.Match("text0<%code0%>text1<%code1%><%%>text3");
string[] text = res2.Groups[1].Captures.Cast<Capture>().Select(p => p.Value).ToArray();
string[] escapes = res2.Groups[2].Captures.Cast<Capture>().Select(p => p.Value).ToArray();

请记住,它需要RegexOptions.ExplicitCapture.

正则表达式将在两组(1 和 2)中捕获字符串外<% %>和内的片段<% %>。每个组由多个Captures 组成。

说明:

( ... )* The outer layer. Any number of captures are possible... So any number of "outside" and "inside" are possible

(?<1>((?!<%).)+) The capturing group 1, for the "outside"

| alternatively

<% An uncaptured <%
(?<2>((?!%>).)*) The capturing group 2, for the "inside"
%> An uncaptured %>

捕获组 1:

(?<1> ... ) The name of the group (1)

和里面:

((?!<%).)+ Any character that isn't a < followed by a % (at least one character)

捕获组 2:

(?<2> ... ) The name of the group (2)

和里面:

((?!%>).)* Any character that isn't a < followed by a % (can be empty)

请注意,如果有一个未关闭的,这个正则表达式将被严重破坏<%!问题是可以解决的。

var rx = new Regex("((?<1>((?!<%).)+)|<%(?<2>((?!<%|%>).)*)%>|(?<3><%.*))*", RegexOptions.ExplicitCapture);

并添加

string[] errors = res2.Groups[3].Captures.Cast<Capture>().Select(p => p.Value).ToArray();

如果errors不为空,则有一个未闭合的<%

现在,如果您想对捕获进行排序:

var captures = res2.Groups[1].Captures.Cast<Capture>().Select(p => new { Text = true, Index = p.Index, p.Value })
    .Concat(res2.Groups[2].Captures.Cast<Capture>().Select(p => new { Text = false, Index = p.Index, p.Value }))
    .OrderBy(p => p.Index)
    .ToArray();

现在,每个捕获都有一个Index, aText可以是trueforTextfalsefor Escape,而 aValue是 的文本Capture

于 2013-08-05T10:39:55.297 回答
0

您可以使用 Regex.Replace

var text = Regex.Replace(input, "<%.+?%>", "");
于 2013-08-05T10:48:49.800 回答
0

尝试这个:

class Program
{
    static void Main(string[] args)
    {
        var input = "text0<%code0%>text1<%code1%><%%>text3";
        List<string>
            text = new List<string>(),
            code = new List<string>();
        var current = 0;
        Regex.Matches(input, @"<%.*?%>")
            .Cast<Match>()
            .ToList().ForEach(m =>
            {
                text.Add(input.Substring(current, m.Index - current));
                code.Add(m.Value);
                current = m.Index + m.Length;
                if(!m.NextMatch().Success)
                    text.Add(input.Substring(current, input.Length - current));
            });
    }
}
于 2013-08-05T10:56:32.120 回答