我的任务是构建一个解析特定网页的解析器,以便我们的员工可以将他们的用户数据批量导入我们公司的网站。
我已经使用 HtmlAgilityPack 来解析页面,我已将table row
和table data
与我Map
类中的属性相关联
然而,一个专栏让我感到很悲伤。由于各种原因,地址列是我身边的荆棘。
示例数据:
6313 SW 203rd Ave <br> Portland, OR 97224
16600 Lomita Way <br> El Dorado Hills, CA 95762
PO Box #42 <br> Hampton Bays, NY 11946
这些地址中的每一个都是这样包装的(显然地址可能因我们导入用户的客户而异):
<tr>
<td> 6313 SW 203rd Ave <br> Portland, OR 97224 </td>
</tr>
我正在尝试实现正则表达式将其拆分到适当的区域,因此可以将其分配给相关属性:
public string Unit { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
然而,这些地址并没有提供太多的东西:
问题一:
如果我锚定<br>
,那么我只是将线分开。没有完全分裂成适当的部分。
第二期: 与单个逗号相同的问题。
第三期: 如果我锚定到数值,则Zip可能对加拿大无效,并且可能根据街道名称错误地拆分。
分隔地址项目的最佳方法是什么?使用Regex?
答案 0 :(得分:5)
解析地址很难;真的很难。 地址没有真正统一的格式,特别是跨国界。 您使用单一RegEx进行此操作的可能性极小。
有关一些示例和更深入的解释,请参阅此其他帖子。 How to parse freeform street/postal address out of text, and into components
答案 1 :(得分:2)
正则表达式可以做什么是有限的,但是这里有一个假设您的地址始终遵循此格式的示例。如果您无法确保您的地址符合特定格式(由您的域强制执行),您将不得不依赖一些更复杂的解决方案,例如在其他答案中讨论的内容。
另请查看Parse usable Street Address, City, State, Zip from a string
编辑:对不起,我忘了这是一个C#问题......但你明白了。
var parseAddress = (function (rx) {
return function parseAddress(html) {
var matches = html.match(rx);
return {
unit: matches[1],
street: matches[2],
city: matches[3],
state: matches[4],
zip: matches[5]
};
};
})(/^(\d*)\s*(.+?)\s*<br>\s*(.+?),\s*(.+?)\s*(\d+)$/);
parseAddress('6313 SW 203rd Ave <br> Portland, OR 97224');
//Object {unit: "6313", street: "SW 203rd Ave", city: "Portland", state: "OR", zip: "97224"}
答案 2 :(得分:0)
好的,所以解析Address
字段非常痛苦。但是我确实设法根据我的特定要求解析数据。
Address
总是在街道和广告之间有一个<br>
。市。所以我做了以下事情:
var splitBasedOnHTML = Regex.Split(column[2], @"\br<br>");
column[]
包含index two
中的地址。因此,在通话结束后,它会自动将我的单位和街道定位在Index Zero
。 City,State和Zip将位于Index One
。
所以我做了另一次分手,打破了City,State和Zip这样:
var splitBasedOnSpace = splitBasedOnHtml[1].Split(' ');
之后我现在最终得到以下内容:
6313 SW 203rd Ave // splitBasedOnHtml[0]
Portland, // splitBasedonSpace[0]
OR // splitBasedOnSpace[1]
97224 // splitBasedOnSpace[2]
所以我只是将我的属性映射到那些单独的数组索引。
这个解决方案使假设该单位是街道的一部分,随着数据被导入另一个网站并且以后可以被特定的人修改,这成为一个好的牺牲。
这就是我解决解析问题的方法,这个解决方案对于这艘船上的其他人来说可能并不可行,但希望这是一个不错的选择或指向一个好的方向。方法是什么样的:
public static Map AddressMapper(IList<string> column)
{
var map = new Map();
var splitBasedOnHTML = Regex.Split(column[2], @"\b<br>");
var splitBasedOnSpace = splitBasedOnHTML[1].Split(' ');
map.Street = splitBasedOnHTML[0];
map.City = splitBasedOnSpace[0].Replace(@",", " ");
map.State = splitBasedOnSpace[1];
map.Zip = spliteBasedOnSpace[2];
return map;
}
答案 3 :(得分:0)
如果您摆脱了html标签,就会有一个功能强大的开源库libpostal,非常适合此用例。有绑定到不同的编程语言。 Libpostal是一个C库,用于使用统计NLP和开放数据来解析/规范世界各地的街道地址。该项目的目标是在世界各地理解每种语言的基于位置的字符串。
我用Python绑定pypostal创建了一个简单的Docker映像,您可以将其剥离并轻松尝试pypostal-docker