【问题标题】:Regex replacement in a custom tag自定义标签中的正则表达式替换
【发布时间】:2020-03-21 12:19:08
【问题描述】:

我有一个可能包含以下一个或多个标签的字符串:

<CHOICE [some words] [other words]>

我需要替换(C#)所有出现的这个标签,如下所示:

Example: I like <CHOICE [cars and bikes] [apple and oranges]>
Result: I like cars and bikes
Example: I like <CHOICE [cars and bikes] [apple and oranges]>, I also like <CHOICE [pizza] [pasta]>
Result: I like cars and bikes, I also like pizza

基本上,只用第一组括号中出现的字符串替换整个标签。

看起来捕获组是要走的路,但我无法理解如何让它们工作。

感谢任何帮助!

编辑:正则表达式不是必需的,我认为这将是最好的方法,但我看到一些 cmets 告诉我不需要它,所以任何其他建议都一样好。谢谢!

【问题讨论】:

  • 这里有正则表达式的替代方法 - 简单地使用第一个左括号和右括号的索引来获取您的文本
  • 这个正则表达式或其他方法不止一步,老实说,你可以用 for 循环做得更快,代码更少
  • 你尝试了什么,什么没用?
  • @TheGeneral 我试图弄清楚如何解决这个问题。首先,我需要将要替换的标签作为一个整体识别出来,然后将其替换为第一个括号的内容。如果同一字符串中有多个标签,则对标签的任何位置重复。到目前为止,我只处理了诸如text = Regex.Replace(text, pattern, "fixedvalue"); 之类的正则表达式替换,所以我有点迷茫......
  • 你是在 HTML 还是 XML 上使用这个?

标签: c# regex replace


【解决方案1】:

只是为了好玩。这是一个校园foreach 状态机,具有线性 O(n) 时间复杂度

var line = "I like <CHOICE [cars and bikes] [apple and oranges]>";

var result = new StringBuilder();
var state = 0;

foreach (char c in line)
{
   if (state == 0 && c == '<') state = 1;
   else if (state == 1 && c == '[') state = 2;
   else if (state == 2 && c == ']') state = 3;
   else if (state == 3 && c == '>') state = 0;
   else if (state == 0 || state == 2) result.Append(c);
};

输出

I like cars and bikes

Demo here

【讨论】:

  • 非常感谢!这适用于标签的第一次出现。使用多个标签(如果之前有不相关的标签,或者有​​多个 CHOICE 标签)会有一些问题,但我认为这是了解如何使其充分发挥作用的一个很好的起点。我根本没有想到这种方法。
  • @Sting1 是的,这只是为了好玩,因为我正在等待我的电梯。正则表达式可能也是一个不错的选择,我用状态机更新了
【解决方案2】:

首先获取匹配组,然后为每个匹配组替换 [] 中的第一个字符串

MatchCollection matches = Regex.Matches(InputStr, @"<CHOICE(.*?)>");

foreach(Match Item in matches)
{
    MatchCollection matches1 = Regex.Matches(Item.ToString(), @"\[(.+?)]");
    string FirstOccurence = matches1[0].Groups[1].ToString();
    InputStr = InputStr.Replace(Item.ToString(), FirstOccurence);
}

找到demo

【讨论】:

  • 我认为这非常有效!我相信只有最后一个子字符串需要调整如下: Substring(1, matches1[0].ToString().Length - 2)
  • 对不起,我做了进一步的编辑,因为我最初的更正中有一个错误。看起来是“长度 - 2”。
  • 评估为汽车和自行车
  • @ArthurGrigoryan 编辑了答案。请检查一下。
  • @Sting1 已删除 .Substring。查看最新答案。
【解决方案3】:
string pattern = @"\< *CHOICE *((\[(?<choice>[a-zA-Z0-9 ]+)\]) *)+ *>";

Regex regex = new Regex(pattern);

string source = "I like <CHOICE [cars and bikes] [apple and oranges]>";

var match = regex.Match(source);
if (match.Success)
{
    for (int i = 0; i < match.Groups["choice"].Captures.Count; i++)
    {

        Debug.WriteLine(match.Groups["choice"].Captures[i]);
    }
    string replaced = regex.Replace(source, match.Groups["choice"].Captures[0].Value);

    Debug.WriteLine(replaced);
}

输出是:
汽车和自行车
苹果和橘子
我喜欢汽车和自行车

\

匹配“

([a-zA-Z0-9 ]+)

匹配单词和空格

?

给上面的组一个名字:choice

\[(?[a-zA-Z0-9 ]+)\]

匹配[]中的一个选项

((\[(?[a-zA-Z0-9 ]+)\] *)

匹配由零个或多个空格分隔的选项

+

意味着你应该至少有一个选择

*>

在“>”之前可以有零个或多个空格

【讨论】:

    【解决方案4】:

    我认为这是最好的方法。

    string text = "This is some dummy text with the choice <    CHOICE     [ white   black green     cyan ] [yellow green]>." +
                " The second choice <CHOICE [pink brown red] [blue cyan]>.";
    string pattern = @"<\s*?CHOICE\s*\[\s*?(.+?)\s*?\].*?>";
    var result = Regex.Replace(text, pattern, r => String.Join(" and ", r.Groups[1].Value.Split(' ', StringSplitOptions.RemoveEmptyEntries)));
    Console.WriteLine(result);
    

    输出

    这是一些虚拟文本,可选择白色和黑色以及绿色和青色。第二选择粉色和棕色和红色。

    【讨论】:

    • 立即尝试并测试它。准备生产:D
    • 您如何知道要删除的空间?
    • @Sushant Yelpale 没明白你的意思,但正则表达式处理所有空格,除了通过拆分和删除空条目处理的选择词之间的空格。
    • 如果输入字符串中有超过 1 个连续空格,则不应在不知道它们的含义的情况下将其删除。就像你在输出中从&lt; CHOICE [ white black green cyan ] [yellow green]&gt; 中删除它们一样
    • @Sushant Yelpale 我想不出任何我们希望在选择之间保留额外空间的情况,因此我试图消除意外。我的意思是,它不能满足所有特殊情况。例如,如果选择用逗号分隔,我们想去掉它怎么办。我们肯定会重写上述逻辑以满足条件。
    猜你喜欢
    • 1970-01-01
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    相关资源
    最近更新 更多