我正在解析地址字符串,并发现有时街道名称包含的单词也是有效的城市名称。我希望确保城市名称的任何第二次出现总是与regex中的最后一个组匹配,并且regex中的第一个组被视为可选。
下面是一些示例输入:
123 SUNNYSIDE AVENUE BROOKLYN
59 MAIDEN LANE MANHATTAN
59 MAIDEN LANE MANHATTAN 10038
39-076 46 STREET SUNNYSIDE
39-076 46 STREET SUNNYSIDE 11104
59 MAIDEN LANE MANHATTAN NY USA理想情况下,为这些函数返回的regex组如下所示:
(123 )(SUNNYSIDE)( AVENUE )(BROOKLYN)
(59 MAIDEN LANE )(null)(null)(MANHATTAN)
(59 MAIDEN LANE )(null)(null)(MANHATTAN)
(39-076 46 STREET )(null)(null)(SUNNYSIDE)
(39-076 46 STREET )(null)(null)(SUNNYSIDE)
(59 MAIDEN LANE )(null)(null)(MANHATTAN)对于城市,我在regex组中有一个列表(本例中是简化的),如下所示:
(MANHATTAN|BROOKLYN|SUNNYSIDE)我的起始正则表达式如下:
(.*?)(?:\W*)(MANHATTAN|BROOKLYN|SUNNYSIDE)(?:.*)当然,这会产生以下结果:
(123)(SUNNYSIDE)我正在尝试扩展它以支持上面提到的情况,但是到目前为止我尝试匹配的1到2个城市总是匹配它找到的第一个城市作为最后一个组,而忽略其余的。
关于地址解析有很多特殊的问题,但现在我只专注于解决这一个特殊的情况。谢谢你的帮助!
发布于 2011-10-28 03:33:12
您的示例输出令人困惑。第一行暗示您想要将街道地址分解为其单独的组成部分,但在其余行中,它全部捆绑在一起。我期望期望的结果是:
"123 SUNNYSIDE AVENUE", "BROOKLYN"
"59 MAIDEN LANE", "MANHATTAN"
"59 MAIDEN LANE", "MANHATTAN"
"39-076 46 STREET", "SUNNYSIDE"
"39-076 46 STREET", "SUNNYSIDE"
"59 MAIDEN LANE", "MANHATTAN"...or:
"123", "SUNNYSIDE", "AVENUE", "BROOKLYN"
"59", "MAIDEN", "LANE", "MANHATTAN"
"59", "MAIDEN", "LANE", "MANHATTAN"
"39-076", "46", "STREET", "SUNNYSIDE"
"39-076", "46", "STREET", "SUNNYSIDE"
"59", "MAIDEN", "LANE", "MANHATTAN"在这两种情况下,我都会将其与下面的正则表达式进行匹配:
^(\S+(?:\s+\S+)*)\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)第一组是贪婪的,因此它最初将消耗地址字符串中除最后一个单词之外的所有单词。如果最后一个单词不是城市名称(也就是说,它与(MANHATTAN|BROOKLYN|SUNNYSIDE)组不匹配),第一组将一次“放弃”一个单词,直到第二组匹配。
假设字符串实际上包含一个城市名称,并且该名称包含在第二个组的子表达式中,则将在组#2中捕获该名称。组#1将包含整个街道地址;如果您希望像上面所示那样将其拆分,可以使用空格将其拆分。
编辑:这里有一些示例代码来演示。特别要注意使用find()而不是matches()。Java的matches()方法的行为让许多人感到惊讶,并认为这可能是这里的问题的一部分。简而言之,find()是我必须在正则表达式的开头添加^的原因,也是为什么我不必在末尾添加.*的原因。;)
String[] ss = {
"123 SUNNYSIDE AVENUE BROOKLYN",
"59 MAIDEN LANE MANHATTAN",
"59 MAIDEN LANE MANHATTAN 10038",
"39-076 46 STREET SUNNYSIDE",
"39-076 46 STREET SUNNYSIDE 11104",
"59 MAIDEN LANE MANHATTAN NY USA"
};
Pattern p = Pattern.compile("^(\\S+(?:\\s+\\S+)*)\\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)");
Matcher m = p.matcher("");
for (String s : ss)
{
if (m.reset(s).find())
{
System.out.printf("%naddr: '%s'%ncity: '%s'%n", m.group(1), m.group(2));
}
}输出:
addr: '123 SUNNYSIDE AVENUE'
city: 'BROOKLYN'
addr: '59 MAIDEN LANE'
city: 'MANHATTAN'
addr: '59 MAIDEN LANE'
city: 'MANHATTAN'
addr: '39-076 46 STREET'
city: 'SUNNYSIDE'
addr: '39-076 46 STREET'
city: 'SUNNYSIDE'
addr: '59 MAIDEN LANE'
city: 'MANHATTAN'发布于 2011-10-28 01:43:39
沿着这条路走下去就是疯狂。地址是无法解析的。在您的例子中,您可以告诉regex引擎,它只能匹配您的城市名称后面的邮政编码或字符串结尾。这应该是可行的:
^(.*?)\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)\s*(\d*)$发布于 2011-10-28 02:12:56
考虑到您的示例集有点有限(考虑到地址可能有多复杂,在压缩到一行时会更复杂,在删除标点符号时会更复杂),而且不知道如何使用所有这些内容,我认为您可能需要以下正则表达式:
^([\w -]*?)(MANHATTAN|BROOKLYN|SUNNYSIDE)(?:[ 0-9-]*)$分解后,这个表达式说:
^ # Assert at beginning
( # Capture the following
[\w -] # Match letters, numbers, [space]'s and hyphens
*? # ...any number of times, but be reluctant
) # <end capture>
(MANHATTAN|BROOKLYN|SUNNYSIDE) # Capture one of these three strings
(?: # Match but do not group the following
[ 0-9-]* # [space]'s, numbers, and hyphens
) # <end match>
$ # Assert end of line这将捕获以下组:
(123 SUNNYSIDE AVENUE ) (BROOKLYN)
(59 MAIDEN LANE ) (MANHATTAN)
(59 MAIDEN LANE ) (MANHATTAN)
(39-076 46 STREET ) (SUNNYSIDE)
(39-076 46 STREET ) (SUNNYSIDE)如果您实际上希望标识街道名称和类型(如SUNNYSIDE和AVENUE作为不同的组),但仅当它们与城市名称相同时,则需要更复杂的表达式。
编辑:你的表达式,当分解时,说:
(.*?) # Match any character except newline, any number of times, but be reluctant
(?:\W*) # Match but do not group any non-word character, any number of times
(MANHATTAN|BROOKLYN|SUNNYSIDE) # Match one of these three strings
(?:.*) # Match but do not group any number of characters except newline您编写的表达式将匹配任何可能的内容,直到一个空格(非单词字符),然后匹配空格,然后尝试将空格后面的内容与一个城市名称相匹配。如果这行得通,那么它就会匹配线路上的任何其他内容。如果它不起作用,它将返回并匹配前面提到的空格,然后匹配所有字符,直到下一个非单词字符。然后,它将匹配空格,并继续循环,直到找到一个城市名称。
围绕\W*的(?:)构造实质上是没有意义的,因为\W*是一个单一的匹配,重复了任意次。
https://stackoverflow.com/questions/7920011
复制相似问题