在R语言中从地址提取街道名的需求与技术求助
R中提取街道名的正则实现方案
需求回顾
从街道地址字符串中提取目标街道名,需遵循以下规则:
- 移除字符串开头的门牌号
- 保留最后一个街道后缀(如RD、ST、DR等)之前的内容,同时满足:
- 若存在两个街道后缀,保留第一个、移除第二个(例:South Pkwy Dr → South Pkwy)
- 若地址以数字(含带字母的数字,如25A)结尾,保留后缀及后续数字内容(例:123 County Rd 53 → County Rd 53)
解决方案代码
使用stringr包结合正则表达式实现,完整代码如下:
library(tidyverse) # 示例数据 d <- tibble(input=c( '505 BLACKBERRY', '135 BEARDSLEY ST', '15 HUNT CLUB DR', '1223 STATE ROUTE 103', '455 STATE RTE 43', '206 COUNTY RD 4710', '17 E 250TH ST', '158 BALLINGER AVE SE', '150 BALLINGER AVE S', '18 BALLINGER AVE T' , '1272 ORANGE SUN TRL', '291 S MORELAND BLVD', '615 RUSSET WOOD LN', '1165 MORROCCO CT', '1321 S PKWY DR', '250 COUNTY RD 25A S', '22 SANSTONE RIDGE WAY', '55070 MENDOZA TRL', '1609 HUNTSMERE AVE DOWN', '243 MISTY WOODS CV S', '2292 BAYBERRY CMNS', '16 KILDEER CRK', '40 BEDFORD XING', '4 LEXINGTON SQ', '113 SPARROWS CRST', '1082 MATHOM LNDG', '1050 WILLOW RIDGE LOOP', '660 REDTOP LOOP', '8 MOUNT ROYAL LOOP', '805 SIERRA OVAL', '3012 NANTUCKET ROW', '6 WOODROW AVE', '943 DARROW PARK DR', '743 BELVEDERE TER', '189 WINCHESTER RD', '19 WHITE OAK TRCE', '890 BLACKJACK RD EXT', '767 N EXCALIBUR DR', '109 VININGS FOREST LN SE', '508 E 141ST ST', '85 ROSE LN ST SW'), output= c( 'BLACKBERRY', 'BEARDSLEY', 'HUNT CLUB', 'STATE ROUTE 103', 'STATE RTE 43', 'COUNTY RD 4710', 'E 250TH', 'BALLINGER', 'BALLINGER', 'BALLINGER' , 'ORANGE SUN', 'S MORELAND', 'RUSSET WOOD', 'MORROCCO', 'S PKWY', 'COUNTY', 'SANSTONE RIDGE WAY', 'MENDOZA', 'HUNTSMERE', 'MISTY WOODS', 'BAYBERRY', 'KILDEER', 'BEDFORD', 'LEXINGTON', 'SPARROWS', 'MATHOM', 'WILLOW RIDGE', 'REDTOP', 'MOUNT ROYAL', 'SIERRA', 'NANTUCKET', 'WOODROW', 'DARROW PARK', 'BELVEDERE', 'WINCHESTER', 'WHITE OAK', 'BLACKJACK', 'N EXCALIBUR', 'VININGS FOREST', 'E 141ST', 'ROSE LN')) # 核心处理逻辑 d <- d %>% mutate( # 第一步:移除开头的门牌号 no_house_num = str_remove(input, "^\\s*\\d+\\s+"), # 第二步:提取目标街道名 extracted = case_when( # 情况1:以数字(含带字母的数字)结尾,保留全部内容 str_detect(no_house_num, "\\b[A-Z0-9]+\\d+$") ~ no_house_num, # 情况2:包含多个街道后缀,保留第一个后缀及之前的内容 str_detect(no_house_num, "\\b(AVE|BLVD|CMNS|CRK|CRST|CT|CV|DR|EXT|LNDG|LN|LOOP|OVAL|PKWY|RD|RTE|ROUTE|ROW|SQ|TER|TRCE|TRL|WAY|XING)\\b\\s+[A-Z]+\\b") ~ str_extract(no_house_num, "^.*?\\b(AVE|BLVD|CMNS|CRK|CRST|CT|CV|DR|EXT|LNDG|LN|LOOP|OVAL|PKWY|RD|RTE|ROUTE|ROW|SQ|TER|TRCE|TRL|WAY|XING)\\b"), # 情况3:只有单个街道后缀,保留后缀之前的内容 TRUE ~ str_remove(no_house_num, "\\b(AVE|BLVD|CMNS|CRK|CRST|CT|CV|DR|EXT|LNDG|LN|LOOP|OVAL|PKWY|RD|RTE|ROUTE|ROW|SQ|TER|TRCE|TRL|WAY|XING)\\b.*$") ) ) # 验证结果是否匹配预期 all(d$extracted == d$output) # 返回TRUE表示匹配成功
正则逻辑说明
- 移除门牌号:
^\\s*\\d+\\s+匹配字符串开头的任意空格+数字+任意空格,直接移除。 - 判断结尾数字:
\\b[A-Z0-9]+\\d+$匹配以数字结尾的字符串(包括25A这类带字母的数字),这类情况直接保留处理后的全部内容。 - 处理多后缀情况:正则
^.*?\\b(后缀列表)\\b非贪婪匹配到第一个街道后缀为止,保留这部分内容。 - 处理单后缀情况:
\\b(后缀列表)\\b.*$匹配从第一个街道后缀到结尾的部分,直接移除,保留后缀之前的内容。
注意事项
- 后缀列表可根据实际需求补充更多街道后缀缩写;
- 若地址中存在小写字母,可在正则中添加
(?i)开启不区分大小写匹配,比如(?i)\\bAVE\\b。
内容的提问来源于stack exchange,提问作者ra_learns
相关产品推荐
相关产品推荐

