0


SqlServer-分词

字符串根据词性拆分分词

在工作中有的时候需要对人工填写的地址与数据库的地址进行匹配,有的时候需要对地址进行拆分,将地址规整。但多数情况下,人工填写是不规范的,因此一个根据词性拆分的方法,以便在拆分时能起到辅助作用。
如:南塘浜路11-15号 (虚拟)
序号分词词性位置1南塘浜路cn1211num53-symbol7415num85号cn10
通过拆分,可以获得“-”前后的数字和文本,这样也便于将字符串规整为连续型地址,如:南塘浜路11号,南塘浜路12号…南塘浜路15号等。注:本文仅介绍拆分成分词的方法。

1/思路

(拿中文文本举例)如下表所示,对每个字符的词性进行判断,如果该字符不是中文(则不算其位置),用字符原来的位置-判断字符为中文词性后的位置,得出来的结果就可以将字符串归类并拼接成分词。
字符原顺序中文字符再次排序分词归类南111(=1-1+1)塘221(=1-1+1)浜331(=1-1+1)路441(=1-1+1)15--16---7--18--59--号1056(=10-5+1)

2/创建表值函数-生成序列表

  • 给字符串生成序列表,这样就获得了字符串原来的位置
createfunction[dbo].[fn_serial_numer](@nint)returnstableasreturnwith t1 as(select1 n unionallselect1),t2 as(select1 n from t1,t1 a,t1 b,t1 c),t3 as(select1 n from t2,t2 a,t2 b,t2 c),t4 as(select1 n from t3,t3 a)selecttop(@n) row_number()over(orderby(select1)) n from t4 
orderby n 
select substring('南塘浜路11-15号',n,1)ch/*单个字符*/,n /*原始顺序*/from fn_serial_numer(len('南塘浜路11-15号'))

chn南1塘2浜3路41516-71859号10

3/创建表值函数-字符串根据词性拆分成分词

createfunction[dbo].[fn_split_by_property](@strvarchar(max))returns@tabletable(
pkid int/*序号*/,keysvarchar(max)/*拆分后的分词*/,property varchar(32)/*词性*/,indexs int/*位置*/)asbegin--新建一个临时表declare@tmptabletable(pkid int,keysvarchar(max),property varchar(32),indexs int)/**1
分词归类
*/;with t0 as(--将字符串拆分成一行行单个字符select substring(@str,n,1)ch/*单个字符*/,n /*原始顺序*/from fn_serial_numer(len(@str))),t1 as(/*只取中文字符*/select ch/*单个字符*/,n/*原始顺序*/,id=row_number()over(orderby n)/*这里对只取中文字符字符排序*/,rid=n-row_number()over(orderby n)+1,'cn' property /*词性*/from t0 
where unicode(ch)between19968and40869/*判断是否是中文字符*/),t2 as(/*只取数字*/select ch,n
,id=row_number()over(orderby n),rid=n-row_number()over(orderby n)+1,'num' property
from t0 
where ch like'%[0-9]%'),t3 as(/*只取英文*/select ch,n
,id=row_number()over(orderby n),rid=n-row_number()over(orderby n)+1,'en' property
from t0 
where ch like'%[a-zA-Z]%'),t4 as(/*除中文、数字、英文之外的字符串*/select ch,n
,id=row_number()over(orderby n),rid=n-row_number()over(orderby n)+1,'symbol' property
from t0  a
wherenotexists(select*from t1 where a.ch=ch)andnotexists(select*from t2 where a.ch=ch)andnotexists(select*from t3 where a.ch=ch)),tmp as(select*from t1 unionselect*from t2 unionselect*from t3 unionselect*from t4
)/**
通过归类和词性,合并成一个个分词,但是顺序会打乱
如:南塘浜路  11  -   15    号 
*/insertinto@tmptable( pkid,keys, property,indexs )select pkid,keys,property,indexs
from(select row_number()over(orderby(select0))pkid/*随机生成序列,方便循环*/,rid
        ,keys=(select''+ch from tmp b where b.rid=a.rid and b.property=a.property orderby b.n for xml path('')),a.property /*词性*/,0 indexs /*关键字符串在原字符串的位置*/from tmp a 
        groupby rid,a.property
        )tmp

/**2/获取分词在字符串中的位置
--循环,获得每个分词在原字符串中的位置,
--每次循环后,将上述取的位置在原字符串中替换成 ' '
--这样即使字符串中相同的分词,也会得到不同的位置
*/declare@iint,@str_tmpvarchar(max),@keysvarchar(max),@indexintset@i=1set@str_tmp=@strset@keys=''set@index=1while@i<=(selectmax(pkid)from@tmptable)beginset@keys=(selectkeysfrom@tmptablewhere pkid=@i)set@index=charindex(@keys,@str_tmp)update@tmptableset indexs=@indexwhere pkid=@iset@str_tmp=stuff (@str_tmp,@index,len(@keys), {fn repeat(' ',len(@keys))})set@i=@i+1endinsert@table( pkid,keys, property,  indexs )select dense_rank()over(orderby indexs) pkid
,keys,property,indexs 
from@tmptablereturnend
select*from dbo.fn_split_by_property('南塘浜路9009号,南塘浜路9999号')

序号分词词性位置1南塘浜路cn129009num53号cn94,symbol105南塘浜路cn1169999num157号cn19


本文转载自: https://blog.csdn.net/weixin_36752088/article/details/125141424
版权归原作者 weixin_36752088 所有, 如有侵权,请联系我们删除。

“SqlServer-分词”的评论:

还没有评论