Regex用于检查指南针方向
本文关键字:方向 指南针 检查 用于 Regex | 更新日期: 2023-09-27 18:19:58
我希望匹配可能出现在街道或位置前缀或后缀中的8个主要方向,例如:
- NMain
- 南I-22
- 格罗弗大街124号东南
这很容易使用蛮力匹配列表进行编码,并在每个街道地址的每个匹配可能性中循环,一次与字符串锚的开头匹配,一次匹配字符串锚的结尾。如果你想看的话,我直率的起点显示在更远的地方。
我的问题是,是否有人对紧凑、快速执行的模式有一些聪明的想法来完成同样的事情。你可以假设:
- 复合方向始终从北/南分量开始。所以我需要匹配东南,但不是东南
- 模式应该而不是匹配[direction]-ern单词,如"Northern"或"Southwestern"
- 匹配将始终在字符串的最开始或最末尾
我正在使用C#,但我只是在寻找一种模式,所以我不强调语言。对于我或未来的读者来说,/s(outh)?/
和@"s(outh)?"
一样好。
SO强调真实的问题,所以仅供参考。我正在分析几十万个讨厌的、未经验证的用户键入的地址字符串。我想检查"街道"字段(由邮政信箱、街道、公寓和直接的无效垃圾组成的自由形式的混乱)的开始或结束是否以指南针方向开始或结束。我试图解构这些自由形式的字符串,以找到类似的地址,这些地址可能是偶然或有意的变化和混淆。
我的直率尝试
核心模式:/n(orth)?|e(ast)?|s(outh)?|w(est)?|n(orth's*east|e|orth's*west|w)|s(outh's*east|e|outh's*west|w)/
在一个函数中:
public static Tuple<Match, Match> MatchDirection(String value) {
string patternBase = @"n(orth)?|e(ast)?|s(outh)?|w(est)?|n(orth's*east|e|orth's*west|w)|s(outh's*east|e|outh's*west|w)";
Match[] matches = new Match[2];
string[] compassPatterns = new[] { @"^(" + patternBase + @")'b", @"'b(" + patternBase + @")$" };
for (int i = 0; i < 2; i++) { matches[i] = Regex.Match(value, compassPatterns[i], RegexOptions.IgnoreCase); }
return new Tuple<Match, Match>(matches[0], matches[1]);
}
在使用中,sourceDt
是一个包含所有地址的表:
var parseQuery = sourceDt.AsEnumerable()
.Select((DataRow row) => {
string addr = ((string)row["ADDR_STREET"]).Trim();
Tuple<Match, Match> dirMatches = AddressParser.MatchDirection(addr);
return new string[] { addr, dirMatches.Item1.Value, dirMatches.Item2.Value };
})
编辑:事实上,这可能是一个错误的答案——所以保留它只是为了让人们不会提出同样的建议——弄清楚"东南"的标记化本身就是一项任务。此外,我仍然怀疑RegExp是否也会非常有用。
原答覆:不要。。。您最初的RegExp尝试已经不可读。
从标记化字符串中查找每个单词的字典("蛮力方法")已经为您提供了长度上的线性时间和每个单词的恒定时间。而且它很容易用新词进行自定义。
(^[nesw][^n's]*)|([nesw][^n's]*$)
因此,这将匹配一条线:
- 以一个单词开头或结尾:
- 从基本方向开始
- 没有其他n(去掉"-en")
Perl/PCRE兼容表达式:
(?xi)
(^)?
'b
(?:
n(?:orth)?
(?:'s* (?: e(?:ast)? | w(?:est)? ))?
|
s(?:outh)?
(?:'s* (?: e(?:ast)? | w(?:est)? ))?
|
e(?:ast)?
|
w(?:est)?
)
'b
(?(1)|$)
我认为C#支持这里使用的所有功能。