oracle正则截取字符串的函数
现在有这么⼀个需求,数据库中的⼀个⼿输的‘籍贯’字段,要按⼀定的规范截取显⽰在报表上,⽐如,如果‘籍贯’的内容是:‘⼭东省潍坊市昌乐县’,那么报表⾥要显⽰为:‘⼭东昌乐’,如果‘籍贯’是⼭东省潍坊市寒亭区那么就要出来⼭东潍坊,简化的基本需求就是这样,取省⼀级和县⼀级,如果县⼀级是个区,那就取到市⼀级,
没有县⼀级的话,是数据不规范,但是先将就着取省⼀级和市⼀级。
要实现这个⽬的,第⼀是要从数据库⾥把相应的字段取出来,第⼆是要写⼀个oracle截取字符串的函数处理下‘籍贯’字段。
第⼀步⽐较简单,就略过,只看我们的截取函数。
create or replace function f_addr(address in varchar2) return varchar2 as
new_addr varchar2(100);
tempstr1 gscodeitems.name%type;
tempstr2 varchar2(100);
oracle切割字符串函数tempstr3 varchar2(100);
tempstr4 varchar2(100);
tempn0 number;
tempn1 number;
tempn2 number;
tempn3 number;
tempnn number;
cursor minzustrs is
select name from gscodeitems desetnm = '411CBC8F-35D8-4634-944B-0C1065782F48’;
begin
/*单字县*/
if REGEXP_COUNT(address, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族县])(县))$') > 0
then new_addr := REGEXP_REPLACE(address, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族县])(县))$', '\1\6县');
/*新疆维吾尔*/
elsif REGEXP_COUNT(address, '^新疆') > 0
then new_addr := REGEXP_REPLACE(address, '^(新疆)(维吾尔⾃治区)((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+)(区|旗))$', '\1\5\8’);
/*特殊处理双民族两个字的民族在前, 策略是把两个字的民族⼲掉,就恢复成正常模式*/
elsif regexp_count(address, '([^族]+)族', 4) >= 2
then tempstr1 := regexp_substr(address, '([^族]{2})族', 3);
for minzustr in minzustrs loop
if tempstr1 = minzustr.name then
tempnn := 1; exit;
else tempnn := 0;
end if; end loop;
if tempnn = 1 then
tempn0 := length(tempstr1);
tempn1 := regexp_instr(address,tempstr1);
tempn2 := tempn1 - 1;
tempn3 := tempn1 + tempn0;
tempstr2 := substr(address,0,tempn2);
tempstr3 := substr(address, tempn3);
tempstr4 := concat(tempstr2,tempstr3);
new_addr := REGEXP_REPLACE(tempstr4, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+)(区|旗))$',
'\1\6\9');
else
tempstr1 := regexp_substr(address, '([^族])族', 3);
tempn0 := length(tempstr1);
tempn1 := regexp_instr(address,tempstr1);
tempn2 := tempn1 - 1;
tempn3 := tempn1 + tempn0;
tempstr2 := substr(address,0,tempn2);
tempstr3 := substr(address, tempn3);
tempstr4 := concat(tempstr2,tempstr3);
new_addr := REGEXP_REPLACE(tempstr4, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+)(区|旗))$', '\1\6\9'); end if; /*特殊处理单民族两个字的民族,先⼲掉⼴西和宁夏,再取族前两个字判断是否合法,如果合法,就⼲掉⼀个字,然后⾛正常流程*/
elsif regexp_count(address, '([^族]+)族', 4) = 1 then
tempstr1 := regexp_substr(address, '([^族]{2})族', 3);
for minzustr in minzustrs loop
if tempstr1 = minzustr.name then
tempnn := 1; exit;
else tempnn := 0;
end if;
end loop;
if tempnn = 1 then
tempn0 := length(tempstr1);
tempn1 := regexp_instr(address,tempstr1);
tempn2 := tempn1 - 1;
tempn3 := tempn1 + tempn0 - 2;
tempstr2 := substr(address,0,tempn2);
tempstr3 := substr(address, tempn3);
tempstr4 := concat(tempstr2,tempstr3);
new_addr := REGEXP_REPLACE(tempstr4, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+)(区|旗))$',
'\1\6\9');
else
new_addr := REGEXP_REPLACE(address, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+)(区|旗))$',
'\1\6\9');
end if;
else
new_addr := REGEXP_REPLACE(address, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+)(区|旗))$',
'\1\6\9');
end if;
return new_addr;
end f_addr;
这个函数⾥,⽐较关键的,其实是⼀个正则表达式,函数主体⽤了⼏个if else 处理⼏种特殊情况,没有
覆盖全部的情况,只是覆盖了⼏种,这个可以稍后讨论,直接看最后⼀个else,这⾥的这个正则就是⽤到的最基本的正则了:
new_addr := REGEXP_REPLACE(address, '^([^省区族]+)(省|(.族)?⾃治区|市)((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+) (区|旗))$',
'\1\6\9');
这个内置函数,查下oracle的API即可,看到含义也跟猜到个差不多,是⼀个返回⼀个新字符串来替代原字符串的功能,此处简单说下,第⼀个参数address,是源字符串,
第⼆个就是我们的正则pattern, 第三个是返回的字符串,第三个参数‘\1\6\9’,如果熟悉正则的同学,可能会觉得似曾相识,这是取⼦表达式⽤的,从左到右,左括号的排序,
就是我们⼦表达式的排序,取第⼀第六第九个⼦表达式,直观的拿出来,就是取 ([^省区族]+)和([^族]+)和(.+),你对了么。
分析下这⾥的这个正则,其实很简单,整体⽤两个括号分为两部分:头和尾。
第⼀个:^([^省区族]+)(省|(.族)?⾃治区|市),
第⼆个:((.+市|.+地区|.+州)?([^族]+)(县|市|.族⾃治县)|((.+)市)?([^族]+)(区|旗))$
简单的说,
第⼀个是匹配省、⾃治区和直辖市的
第⼆个是匹配市县两级和市区两级的,
\1⾃然是取省的名称,⽐如:⼭东省潍坊市昌乐县,\1就会取到:⼭东,
\6是取县⼀级的名称的,⽐如:⼭东省潍坊市昌乐县,\6就会取到:昌乐,
\9是取省市区这种⾏政级别的市⼀级的名称,⽐如:⼭东省潍坊市寒亭区,\9就会取到潍坊
当表达式匹配到\6的时候,\9的返回值会是空字符串,匹配到\9的时候,\6也会返回空字符串,所以这⼀个表达式,妥妥的满⾜我们的需求,其他的情况,在这⾥先不表,就是特殊处理了下民族⾃治县,⾃治州,新疆啊等。
欢迎同学们有疑问的共同探讨。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论