首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解析可能出现2次相同字符串的字符串

解析可能出现2次相同字符串的字符串
EN

Stack Overflow用户
提问于 2011-10-28 01:37:48
回答 3查看 139关注 0票数 3

我正在解析地址字符串,并发现有时街道名称包含的单词也是有效的城市名称。我希望确保城市名称的任何第二次出现总是与regex中的最后一个组匹配,并且regex中的第一个组被视为可选。

下面是一些示例输入:

代码语言:javascript
复制
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组如下所示:

代码语言:javascript
复制
(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组中有一个列表(本例中是简化的),如下所示:

代码语言:javascript
复制
(MANHATTAN|BROOKLYN|SUNNYSIDE)

我的起始正则表达式如下:

代码语言:javascript
复制
(.*?)(?:\W*)(MANHATTAN|BROOKLYN|SUNNYSIDE)(?:.*)

当然,这会产生以下结果:

代码语言:javascript
复制
(123)(SUNNYSIDE)

我正在尝试扩展它以支持上面提到的情况,但是到目前为止我尝试匹配的1到2个城市总是匹配它找到的第一个城市作为最后一个组,而忽略其余的。

关于地址解析有很多特殊的问题,但现在我只专注于解决这一个特殊的情况。谢谢你的帮助!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-10-28 03:33:12

您的示例输出令人困惑。第一行暗示您想要将街道地址分解为其单独的组成部分,但在其余行中,它全部捆绑在一起。我期望期望的结果是:

代码语言:javascript
复制
"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:

代码语言:javascript
复制
"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"

在这两种情况下,我都会将其与下面的正则表达式进行匹配:

代码语言:javascript
复制
^(\S+(?:\s+\S+)*)\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)

第一组是贪婪的,因此它最初将消耗地址字符串中除最后一个单词之外的所有单词。如果最后一个单词不是城市名称(也就是说,它与(MANHATTAN|BROOKLYN|SUNNYSIDE)组不匹配),第一组将一次“放弃”一个单词,直到第二组匹配。

假设字符串实际上包含一个城市名称,并且该名称包含在第二个组的子表达式中,则将在组#2中捕获该名称。组#1将包含整个街道地址;如果您希望像上面所示那样将其拆分,可以使用空格将其拆分。

编辑:这里有一些示例代码来演示。特别要注意使用find()而不是matches()。Java的matches()方法的行为让许多人感到惊讶,并认为这可能是这里的问题的一部分。简而言之,find()是我必须在正则表达式的开头添加^的原因,也是为什么我不必在末尾添加.*的原因。;)

代码语言:javascript
复制
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));
  }
}

输出:

代码语言:javascript
复制
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'
票数 1
EN

Stack Overflow用户

发布于 2011-10-28 01:43:39

沿着这条路走下去就是疯狂。地址是无法解析的。在您的例子中,您可以告诉regex引擎,它只能匹配您的城市名称后面的邮政编码或字符串结尾。这应该是可行的:

代码语言:javascript
复制
^(.*?)\s+(MANHATTAN|BROOKLYN|SUNNYSIDE)\s*(\d*)$
票数 3
EN

Stack Overflow用户

发布于 2011-10-28 02:12:56

考虑到您的示例集有点有限(考虑到地址可能有多复杂,在压缩到一行时会更复杂,在删除标点符号时会更复杂),而且不知道如何使用所有这些内容,我认为您可能需要以下正则表达式:

代码语言:javascript
复制
^([\w -]*?)(MANHATTAN|BROOKLYN|SUNNYSIDE)(?:[ 0-9-]*)$

分解后,这个表达式说:

代码语言:javascript
复制
^                                # 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

这将捕获以下组:

代码语言:javascript
复制
(123 SUNNYSIDE AVENUE )     (BROOKLYN)
(59 MAIDEN LANE )           (MANHATTAN)
(59 MAIDEN LANE )           (MANHATTAN)
(39-076 46 STREET )         (SUNNYSIDE)
(39-076 46 STREET )         (SUNNYSIDE)

如果您实际上希望标识街道名称和类型(如SUNNYSIDEAVENUE作为不同的组),但仅当它们与城市名称相同时,则需要更复杂的表达式。

编辑:你的表达式,当分解时,说:

代码语言:javascript
复制
(.*?)                            # 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*是一个单一的匹配,重复了任意次。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7920011

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档