C# 这个正则表达式替换如何反转字符串?

C# 这个正则表达式替换如何反转字符串?,c#,java,regex,lookaround,nested-reference,C#,Java,Regex,Lookaround,Nested Reference,这是教育正则表达式系列文章的第四部分。它展示了如何将嵌套引用(请参见:)与断言(请参见:)中的“计数”相结合来反转字符串。通过编程生成的模式使用元模式抽象(请参阅:)。在本系列中,这些技术首次用于替换而不是整个字符串匹配 提供了完整的工作Java和C#实现。包括鼓舞人心的名言 使用正则表达式反转字符串似乎从来都不是一个好主意,如果它是完全可能的,或者如果是的话,人们可能会如何尝试这样做,也不是很明显 虽然这仍然不是一个好主意,但至少现在我们知道这是可能的,因为有一种方法可以做到: C#() 使用

这是教育正则表达式系列文章的第四部分。它展示了如何将嵌套引用(请参见:)与断言(请参见:)中的“计数”相结合来反转字符串。通过编程生成的模式使用元模式抽象(请参阅:)。在本系列中,这些技术首次用于替换而不是整个字符串匹配

提供了完整的工作Java和C#实现。包括鼓舞人心的名言

使用正则表达式反转字符串似乎从来都不是一个好主意,如果它是完全可能的,或者如果是的话,人们可能会如何尝试这样做,也不是很明显

虽然这仍然不是一个好主意,但至少现在我们知道这是可能的,因为有一种方法可以做到:

C#()
使用系统;
使用System.Text.RegularExpressions;
公共类二元通用{
公共静态void Main(){
字符串反向=
@“(?sx)。抓取2美元”
.替换(“抓取2美元”,
前驱(
资产后缀(@“(.1?))
)
);
控制台写入线(
Regex.Replace(
@“尼茨尼·特雷布拉--
他说:“我的名字是诺德,我的名字是尼亚尔帕克。”,
反面“$2”
)
);
//如果你不能简单地解释它,你就不能很好地理解它
//--阿尔伯特·爱因斯坦
}      
//对当前位置后面的每个点执行断言
静态字符串ForEachDotBehind(字符串断言){
返回“(?概述
在较高级别上,模式匹配任何一个字符
,但另外执行
抓取$2
操作,该操作捕获反转“mate”"匹配到第2组的字符的后缀。此捕获是通过构建输入字符串的后缀来完成的,该字符串的长度与前缀的长度匹配到当前位置。我们通过在将后缀增加一个字符的模式上应用
assertSuffix
,重复此操作一次
forEachDotBehind
。第1组cap在第2组中,该后缀的第一个字符是匹配字符的反转“mate”

因此,将每个匹配的字符替换为其“mate”具有反转字符串的效果


工作原理:一个简单的例子 为了更好地理解正则表达式模式是如何工作的,我们首先将其应用于一个更简单的输入。此外,对于我们的替换模式,我们将“转储”所有捕获的字符串,以便更好地了解发生了什么。下面是一个Java版本:

System.out.println(
    "123456789"
        .replaceAll(REVERSE, "[$0; $1; $2]\n")
);
以上打印内容():

因此,例如,
[3;789;7]
表示点匹配的
3
(在组0中捕获),相应的后缀是
789
(组1),其第一个字符是
7
(组2)。请注意
7
3
的“配偶”

请注意,角色的“伴侣”可能在其右侧或左侧。角色甚至可能是其自己的“伴侣”


后缀的生成方式:嵌套引用 负责匹配和构建增长后缀的模式如下:

    ((.) \1?)
    |\_/    |
    | 2     |       "suffix := (.) + suffix
    |_______|                    or just (.) if there's no suffix"
        1
请注意,在组1的定义中是对自身的引用(使用
\1
),尽管它是可选的(使用
)。可选部分提供了“基本情况”,一种组在不引用自身的情况下进行匹配的方法。这是必需的,因为当组尚未捕获任何内容时,匹配组引用的尝试总是失败

一旦第1组捕获了某些内容,我们的设置中就不会使用可选部分,因为我们上次捕获的后缀这次仍然存在,并且我们可以始终使用
(.)
将另一个字符前置到此后缀的开头。此前置字符被捕获到第2组中

因此,此模式尝试将后缀增加一个点。因此,重复此操作一次
forEachDotBehind
将产生一个后缀,其长度正好是前缀到当前位置的长度


assertSuffix
forEachDotBehind
如何工作:元模式抽象 请注意,到目前为止,我们已经将
assertSuffix
forEachDotBehind
视为黑匣子。事实上,将此讨论放在最后是一种深思熟虑的行为:名称和简要文档表明了它们的作用,这些信息足以让我们编写和阅读我们的
反向
模式

仔细观察,我们发现这些抽象的Java和C#实现略有不同,这是由于两个正则表达式引擎之间的差异

NET正则表达式引擎允许在lookback中使用完整的正则表达式,因此这些元模式在这种风格中看起来更自然


  • AssertSuffix(pattern):=(?=.*$)(?关于meta的系列讨论:嗯,非常漂亮(系列概念总体上很有趣)。我认为即使对于那些不精通正则表达式的人来说,解释也相当清楚,尽管我希望害怕它们的人不要在看到“巫毒魔法”后逃跑蒂姆:从现在起,我打算开始写中级的东西,没有什么比这更“高级”的了。我会继续用“有趣”的例子来让学习更有趣。我喜欢这样,即使没有警告;)+1*。该死的可变长度lookbehinds!你可以从中获得很多乐趣。可惜我们在Perl/PCRE中没有这些。关于正则表达式的一系列问题/答案很棒。:-)哦,对于那些感兴趣的人(比如我),完整的C表达式是:
    (?sx)。(?
    
    System.out.println(
        "123456789"
            .replaceAll(REVERSE, "[$0; $1; $2]\n")
    );
    
    [1; 9; 9]
    [2; 89; 8]
    [3; 789; 7]
    [4; 6789; 6]
    [5; 56789; 5]
    [6; 456789; 4]
    [7; 3456789; 3]
    [8; 23456789; 2]
    [9; 123456789; 1]
    
                       current position after
                          the dot matched 3
                                  ↓        ________
                          1  2 [3] 4  5  6 (7) 8  9
                          \______/         \______/
                           3 dots        corresponding
                           behind      suffix of length 3
    
        ((.) \1?)
        |\_/    |
        | 2     |       "suffix := (.) + suffix
        |_______|                    or just (.) if there's no suffix"
            1