删除可选的最后一个括号

时间:2019-07-23 14:21:35

标签: c# regex

我正在尝试解析文件名并删除括号中的潜在数字(当多个具有相同基本名称的文件时),但是只有最后一个

以下是一些预期结果:

  1. Test ==> Test
  2. Test (1) ==> Test
  3. Test (1) (2) ==> Test (1)
  4. Test (123) (232) ==> Test (123)
  5. Test (1) foo ==> Test (1) foo

我尝试使用此正则表达式:(.*)( ?\(\d+\))+,但测试1失败。

我也尝试过:(.*)( ?\(\d+\))?,但只有第一个测试成功。

我怀疑正则表达式中的量词有问题,但我找不到确切的内容。

如何修复我的正则表达式?

6 个答案:

答案 0 :(得分:4)

我的猜测是,您可能希望设计一个类似于以下内容的表达式:

^(.*?)\s*(\(\s*\d+\)\s*)?$

测试

using System;
using System.Text.RegularExpressions;

public class Example
{
    public static void Main()
    {
        string pattern = @"^(.*?)\s*(\(\s*\d+\)\s*)?$";
        string input = @"Test
Test (1)
Test (1) (2)
Test (1) (2) (3)
Test (1) (2)    (3) (4) 
";
        RegexOptions options = RegexOptions.Multiline;

        foreach (Match m in Regex.Matches(input, pattern, options))
        {
            Console.WriteLine("'{0}' found at index {1}.", m.Value, m.Index);
        }
    }
}

该表达式在regex101.com的右上角进行了解释,如果您想探索/简化/修改它,在this link中,您可以观察到它如何与某些示例输入匹配,如果你喜欢。

RegEx电路

jex.im可视化正则表达式:

enter image description here

答案 1 :(得分:2)

只用一个负数。前瞻:

\s*\([^()]+\)(?!.*\([^()]+\))

请参见a demo on regex101.com


更详细的是

\s*              # whitespaces, eventually
\([^()]+\)       # (...)
(?!.*\([^()]+\)) # neg. lookahead, no (...) must follow

答案 2 :(得分:2)

作为替代方案,您可以使用字符串结尾/行锚:

正则表达式

\s*\(\d+\)$

可视化

enter image description here

用法示例

string resultString = null;
try {
    resultString = Regex.Replace(subjectString, @"\s*\(\d+\)$", "", RegexOptions.Multiline);
} catch (ArgumentException ex) {
    // Syntax error in the regular expression
}


人类可读

  • 匹配单个字符,即“空白字符”(任何Unicode分隔符,制表符,换行符,回车符,垂直制表符,换页符,下一行)\s*
    • 在零次和无限制次数之间进行尽可能多的次数,并根据需要进行回馈(贪婪)*
  • 匹配开头的括号字符\(
  • 匹配单个字符,即“数字”(任何Unicode脚本中的任何十进制数字)\d+
    • 一次至无限次,尽可能多次,并根据需要回馈(贪婪)+
  • 匹配右括号\)
  • 在行尾(在字符串末尾或换行符之前)声明位置(换行)$

答案 3 :(得分:1)

如果只希望第二个表达式可以做,则可以一起避免使用正则表达式:

string example = @"Test (1) (2)    (3) (4)";

public string GetPathName(string input)
{
     var position = input.LastIndexOf('(');
     if(position == -1)
          return input;

     return example.Substring(0, position);
}

您知道左括号将始终位于结尾名称的开头,那么为什么不找到该索引的索引,然后从零位置获取其余的索引呢?我知道您要求使用正则表达式,但是如果不需要它,为什么要为此过度设计呢?

答案 4 :(得分:1)

您可以使用第一个模式(.*)( ?\(\d+\))+并仅替换为第一个捕获组。

要对其进行优化,可以在最后一个组之后删除量词+,并省略第二个捕获组。

这将通过匹配直到字符串的末尾,然后回溯直到最后一次出现带数字的括号,来删除最后一个带有数字的括号。

在替换中,使用第一个捕获组:

^(.*) \(\d+\)

说明

  • ^字符串的开头
  • (.*)捕获组1,匹配任何char 0次以上
  • (\d+)匹配空间,( 1个以上的数字)

.NET Regex demo | C# demo

enter image description here

答案 5 :(得分:-1)

这适用于您发布的一些示例方案:

(.*)( \(\d+\))

结果:

enter image description here

这是regex101的完整说明:(demo

相关问题