这个正则表达式替换如何反转字符串?C#(也在 ideone.com 上) Java(也在 ideone.com 上)
这是一系列教育正则表达式文章中的第四部分。它显示了嵌套引用(参见:这个正则表达式如何找到三角形数字?)的组合在断言中“计数”(参见:我们如何将a^n b^n与Java正则表达式匹配?)可以用来反转字符串。以编程方式生成的模式使用元模式抽象(请参阅:此 Java 正则表达式如何检测回文?)。在本系列中,这些技术首次用于替换,而不是整个字符串匹配。
提供了完整的工作 Java 和 C# 实现。包括鼓舞人心的名言。
使用正则表达式反转字符串似乎从来都不是一个好主意,如果有可能,甚至也不会立即变得明显,如果是这样,人们可能会如何尝试这样做。
虽然这仍然不是一个好主意,但至少现在我们知道这是可能的,因为这里有一种方法可以做到这一点:
C#(也在 ideone.com 上)
using System;
using System.Text.RegularExpressions;
public class TwoDollarReversal {
public static void Main() {
string REVERSE =
@"(?sx) . grab$2"
.Replace("grab$2",
ForEachDotBehind(
AssertSuffix(@"((.) \1?)")
)
);
Console.WriteLine(
Regex.Replace(
@"nietsniE treblA --
hguone llew ti dnatsrednu t'nod uoy ,ylpmis ti nialpxe t'nac uoy fI",
REVERSE, "$2"
)
);
// If you can't explain it simply, you don't understand it well enough
// -- Albert Einstein
}
// performs an assertion for each dot behind current position
static string ForEachDotBehind(string assertion) {
return "(?<=(?:.assertion)*)".Replace("assertion", assertion);
}
// asserts that the suffix of the string matches a given pattern
static string AssertSuffix(string pattern) {
return "(?=.*$(?<=pattern))".Replace("pattern", pattern);
}
}
Java(也在 ideone.com 上)
class TwoDollarReversal {
public static void main(String[] args) {
String REVERSE =
"(?sx) . grab$2"
.replace("grab$2",
forEachDotBehind(
assertSuffix("((.) \\1?)")
)
);
System.out.println(
"taerG eht rednaxelA --\nyrt lliw ohw mih ot elbissopmi gnihton si erehT"
.replaceAll(REVERSE, "$2")
);
// There is nothing impossible to him who will try
// -- Alexander the Great"
}
static String forEachDotBehind(String assertion) {
return "(?<=^(?:.assertion)*?)".replace("assertion", assertion);
}
static String assertSuffix(String pattern) {
return "(?<=(?=^.*?pattern$).*)".replace("pattern", pattern);
}
}
C# 和 Java 版本似乎都使用相同的整体算法,只是在抽象的实现细节上有细微的变化。
显然,这不是反转字符串的最佳,最直接,最有效的方法。也就是说,为了学习正则表达式;如何将模式概念化;引擎如何工作以匹配它们;如何将各个部分放在一起以构建我们想要的东西;如何以可读和可维护的方式做到这一点;只是为了学习新事物的纯粹乐趣,我们能解释一下它是如何工作的吗?
附录:备忘单!
以下是对所使用的基本正则表达式构造的简要描述:
-
(?sx)
是嵌入式标志修饰符。 启用“单行”模式,允许点匹配任何字符(包括换行符)。 启用自由间距模式,其中忽略未转义的空格(可用于注释)。s
x
#
-
^
并且是线的起点和终点锚点。$
-
?
作为重复说明符表示可选(即零或一)。作为重复量词,例如 它表示(即零个或多个)重复是不情愿/不贪婪的。.*?
*
-
(…)
用于分组。 是非捕获组。捕获组保存它匹配的字符串;它允许后退/前进/嵌套引用(例如),替换替换(例如)等。(?:…)
\1
$2
-
(?=…)
是一个积极的展望;它看起来有权断言给定模式的匹配。 是一个积极的眼光;它向左看。(?<=…)