当前位置: 首页 > 科技观察

如何用有限状态机识别地址的有效性?

时间:2023-03-14 22:14:26 科技观察

在收发快递填写地址的时候,我们经常会手动输入地址让程序进行智能识别。例如,标准地址是xx省xx市xx县/区xx路xx号,但有时也可以简单写成:xx市xx县/区xx路xx号,或xx号。xx省xx县/区xx路xx号,或xx市xx路xx号。但有些地址不是合法地址,如xx省xx街xx号,或xx市xx省xx区xx号。那么问题来了,如何识别一个地址是否有效,准确的说,如何编程识别一个中文地址是否有效?虽然我们的大脑一眼就能识别出来,但计算器却不容易识别出来。根本原因在于地址描述虽然看起来简单,但它仍然是一个比较复杂的上下文相关语法。例如“上海市北京东路xx号,南京市北京东路xx号”。扫描到北京东路时,后面的门牌号是否构成正确的地址,要看上下文,即城市名。幸运的是,地址的上下文相对简单且有限,尽管我们可以暴力破解所有的省、市、区和街道。但有效的方法是有限状态机。每个有限状态机都有一个开始状态和一个结束状态,以及几个中间状态。每条弧携带一个状态进入下一个状态。比如上图中当前state是一个省,如果遇到下一个phrase是和district相关的就进入district,如果下一个phrase是和city相关的,那么就进入city。如果一个地址能从状态机的起始状态,经过状态机的几个中间状态,最后到达结束状态,那么这个地址就是有效的,否则就是无效的。比如xx省xx区xx号xx市就是一个无效地址,从市里走到省内是不可能的。现在我们通过一个简单的优先级状态机来实现,代码有注释,从enumimportEnumdefisAddress(address:str)->bool:#DefinethestateState=Enum("State",["STATE_INITIAL",#开始“STATE_PROVINCE”,#province“STATE_CITY”,#city“STATE_AREA”,#district/county“STATE_STREET”,#street“STATE_NUM”,#number“STATE_END”,#end“STATE_ILLEGAL”,#errorstate])deftoAddressType(addr_slice:str)->State:if"province"inaddr_slice:returnState.STATE_PROVINCEelif"city"inaddr_slice:returnState.STATE_CITYelif"district"inaddr_sliceor"county"inaddr_slice:returnState.STATE_AREAelif"road"inaddr_sliceor"street"inaddr_slice":returnState.STATREE.slicein":returnState.STATE_NUMelse:returnState.STATE_ILLEGAL#definestatetransfertransfer={#开始可以转省市State.STATE_INITIAL:{State.STATE_PROVINCE,State.STATE_CITY,},#省可以转市或区State.STATE_PROVINCE:{State.STATE_CITY,State.STATE_AREA,},#可以转移到的城市区或街道State.STATE_CITY:{State.STATE_AREA,State.STATE_STREET,},#区县可转街道State.STATE_AREA:{State.STATE_STREET,},#街道可以转移或终止State.STATE_STREET:{State.STATE_NUM,State.STATE_END,},#号码只能转移终止State.STATE_NUM:{State.STATE_END,},}st=State.STATE_INITIALforchinaddress:current_state=toAddressType(ch)ifcurrent_statenotintransfer[st]:returnFalsest=current_statereturnstin[State.STATE_STREET,State.STATE_NUM,State.STATE_END]if__name__=='__main__':address1=["江苏省份","苏州市","吴中区","中山北路","208号"]address2=["苏州市","吴中区","中山北路","208号"]address3=["苏州市","吴江区","中山北路","208号"]address4=["苏州市","吴江区","208号"]address5=["苏州市","中山北路""]assertisAddress(address1)assertisAddress(address2)assertisAddress(address3)assertisAddress(address5)assertisAddress(address4)==False这里没有对整个地址字符串进行分段,而是直接将地址写入tten以列表的形式,主要是为了说明状态机的实现和应用,上面的代码只能从格式上保证地址有效,不能保证地址真实有效。如果要判断它是否真实有效,需要建立全国所有的省、市、区、县、街道。哈希表、门等级可以用范围来表示,然后判断状态转移。上面代码的转账是一个哈希表,相当于穷举了所有正确转账的情况。它耗尽了对应于任何情况的任何输入。逃脱状态。本文转载自微信公众号“Python7号”,可通过以下二维码关注。转载本文请联系Python七号公众号。