【问题标题】:Regex exclude specific character not working正则表达式排除特定字符不起作用
【发布时间】:2021-10-27 02:18:25
【问题描述】:

我搜索并发现[^?] 不会包含某个字符,例如本例中的问号,但它似乎包含一个空格,这不是我想要的。这种模式:

\((.*?)\)[^?]

匹配括号中的任何内容,除非最后一个括号后面有问号。

(need to capture including brackets) ignore this
(ignore this completely)?

此模式正确捕获括号中的顶行而不包含空格,但还捕获了我想忽略的行:

\((.*?)\)

我可以使用什么模式只捕获顶行而没有尾随空格而忽略下面的行?

您可以看到这些模式都不能正常工作:

https://regex101.com/r/fHXJ8x/1

https://regex101.com/r/fHXJ8x/2

【问题讨论】:

  • [^?] 在这里捕获除问号以外的任何内容,尝试(?<=\?)
  • @Ghost Ops 你的意思是\((.*?)\)(?<=\?)?如果是这样,那是行不通的。
  • 为什么不能直接剥离结果?不过这很容易......
  • @Ghost Ops 我想你有一些想法,但不清楚它是什么。
  • 我的意思是,将strip() 方法应用于结果以排除字符串末尾的空格。我明白了,你明白我的意思了吗?

标签: regex regex-negation


【解决方案1】:

试试这个正则表达式...

它可以工作,忽略括号内的任何文本,它也在问号旁边

同时忽略不需要的空格

\((.*?)\)(?!\?)

输出:

【讨论】:

  • 嘿,这行得通!看来你终于找到了。
  • 它实际上应该是这个\((.*?)\)(?!\?),否则它会失去我原始模式的功能。无论如何,我已经编辑了你的答案,所以只要批准它就可以了。
  • 是的,我只是无缘无故地将整个正则表达式插入到一个类中,这绝对不会改变功能,但没关系,你是对的@Hasen。无论如何,感谢您的编辑
  • Np,感谢您的回答,这正是我想要的。
【解决方案2】:

首先,您不能使用否定字符类([^?]),因为它是一个消耗模式,即正则表达式引擎将匹配的文本放入匹配内存缓冲区并推进正则表达式匹配结束位置的索引。这就是为什么它匹配那个空格。您需要使用 否定的前瞻,它是一个非消耗模式(?!\?),它不会将匹配的文本添加到匹配中。

其次,当您限制后续模式的上下文时,您不应依赖.*?,因为此模式可以匹配任意数量的任何文本(默认情况下换行符除外)。如果您有... (...)? and () ...,则\(.*?\)(?!\?) 将匹配最左边的(,直到最左边的) 不紧跟? 字符,即匹配将是(...)? and (),请参阅this regex demo

解决方案是避免在括号之间匹配()

\(([^()]*)\)(?!\?)

请参阅regex demo详情

  • \( - 一个 ( 字符
  • ([^()]*) - 第 1 组:除 () 之外的零个或多个字符
  • \) - 一个 ) 字符
  • (?!\?) - 如果在当前位置右侧有一个 ? 字符,则匹配失败(这里的“失败”意味着正则表达式引擎将回溯以查看它是否可以以另一种方式匹配字符串)。

【讨论】:

    【解决方案3】:

    好吧,你可以使用这样的东西:

    (\(.+\)\?)|(\(.*\))

    您不能只忽略第二个字符串,因为根据您的要求,它们是相同的。每个都包含括号。

    但是你可以在正则表达式中定义两个组并且只使用第二个

    (需要捕获包括括号)忽略这个$2

    (完全忽略这个)? $1

    【讨论】:

    • 您实际上捕获了他不想捕获的问号,但无论如何,它不包含问号后面的任何字符。所以@Hasen,我猜你可以运行endswith('?') 方法来删​​除它......
    • (\(.*\)\??)怎么样
    • 如果有新要求,只需添加[] 并将任何需要的字符添加到(\(.+\)[?!&])|(\(.*\))
    • this (\ (. * \) \ ??) 将抓取示例中的第二行,但它不应该是
    【解决方案4】:

    这是一个用 C# 编写的示例程序 - cmets 描述了在 cmets 的反馈过程中发生的变化,正则表达式按照它们在本文中出现的顺序排列。

    // Porgram has been modifed in accordance with the dabate in the comments section
    using System;
    using System.Text.RegularExpressions;
    
    namespace CS_Regex
    {
        class Program
        {
            // Match parenthesized texts that aren't followed by a question mark.
            static void Main(string[] args)
            {
                string[] tests =
                {
                    "(match this text) ignore this (ignore this)? and (match this) (and this)"
                };
                // The first three patterns matches, if the left parenthesis is not the last character.
                // The last pattern matches all parenthesized texts.
                string[] patterns = {
                    @"\((.*?)\)[^?]", // Original regex
                    @"\((.*)\)[^?]", // Regex that matches greedily, which was my first example, that caused the discussion in the comments.
                                     // I asked "Why do you have a question mark after matching zero or more characters?"
                    @"(\([^)]*\))[^?]", // Regex that only matches if the left parenthesis is followed by another character, avoiding the use of the '?' operator.
                    @"(\([^)]*\))(?!\?)", // Regex that matches all instances
                };
                foreach (string pattern in patterns) {
                    Regex rx = new Regex(pattern, RegexOptions.Compiled);
                    Console.WriteLine($"Regex: {pattern}");
                    foreach (string data in tests)
                    {
                        MatchCollection matches = rx.Matches(data);
                        Console.WriteLine($"{matches.Count} matches found in: {data}");
                        foreach (Match match in matches)
                            Console.WriteLine($"   matched value and group: '{match.Value}' and '{match.Groups[1]}'");
                    }
                }
                Console.ReadKey();
            }
        }
    }
    

    程序产生以下输出:

    Regex: \((.*?)\)[^?]
    2 matches found in: (match this text) ignore this (ignore this)? and (match this) (and this)
       matched value and group: '(match this text) ' and 'match this text'
       matched value and group: '(ignore this)? and (match this) ' and 'ignore this)? and (match this'
    Regex: \((.*)\)[^?]
    1 matches found in: (match this text) ignore this (ignore this)? and (match this) (and this)
       matched value and group: '(match this text) ignore this (ignore this)? and (match this) ' and 'match this text) ignore this (ignore this)? and (match this'
    Regex: (\([^)]*\))[^?]
    2 matches found in: (match this text) ignore this (ignore this)? and (match this) (and this)
       matched value and group: '(match this text) ' and '(match this text)'
       matched value and group: '(match this) ' and '(match this)'
    Regex: (\([^)]*\))(?!\?)
    3 matches found in: (match this text) ignore this (ignore this)? and (match this) (and this)
       matched value and group: '(match this text)' and '(match this text)'
       matched value and group: '(match this)' and '(match this)'
       matched value and group: '(and this)' and '(and this)'
    

    该示例已经过编辑,以反映 cmets 中的讨论。

    【讨论】:

    • "为什么匹配零个或多个字符后会有问号?" 是a lazy quantifier,防止正则表达式过度匹配。例如,模式\((.*)\) 和输入(a) (b) 捕获的组将是a) (b,而如果量词是惰性的,那么它只会捕获a。另见What is the difference between .*? and .* regular expressions?
    • 我认为您指的是原始帖子,而不是我的。自 1988 年以来,我一直在定期使用正则表达式,并准确指出您所写的内容。
    • 你问的是问号。而且似乎不是一个反问,因为在您的帖子中没有答案。当然,如果您很熟悉,那么您就会知道您已经更改了模式的匹配方式,现在结果与 OP 的不同。
    • 我用了他原来的正则表达式并写了问号是不必要的。大声笑。
    猜你喜欢
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    • 2016-07-03
    相关资源
    最近更新 更多