SAS - 正则表达式

SAS - 正则表达式

正则表达式(Regular Expression)是一种文本模式,可用于文本的匹配、查找和替换。Base SAS 内置了正则表达式的实现,并提供了一系列 PRX- 函数及 CALL 子程序,便于对文本进行更为灵活的处理。

正则表达式的结构

正则表达式由普通字符和元字符组成。元字符用于匹配符合特定规则的字符集合,例如:数字、字母、标点符号等字符集合。

元字符又分为:基本元字符、定界符、限定符等。

基本元字符

常用的基本元字符如下:

  • \d : 匹配数字0-9
  • \n : 匹配换行符
  • \s : 匹配空白字符,包括空格、制表符等
  • \t : 匹配制表符
  • \w : 匹配任何单词字符、数字字符、下划线

例如:\d\d 将匹配两个连续的数字。

定界符

定界符用于限定匹配字符串的边界。

  • ^ : 匹配字符串的开头
  • $ : 匹配字符串的结尾
  • \b : 匹配一个单词的边界
  • \B : 匹配一个单词的非边界

例如:^apple$ 只能匹配单词 apple,这是因为使用了定界符,^ 限制匹配的单词只能以 a 开头,$ 限制匹配的单词只能以 e 结束。如果不加定界符,apple 不仅可以匹配单词 apple,还可以匹配单词 pineapple 中的 apple。

限定符

限定符用于限制某个匹配模式的重复次数,不使用限定符的情况下是匹配一次。

  • {n} : 匹配 n 次
  • {n,} : 匹配至少 n 次
  • {n,m} : 匹配至少 n 次,至多 m 次
  • * : 匹配 0 次或更多次,等价于 {0,}
  • + : 匹配 1 次或更多次,等价于 {1,}
  • ? : 匹配 0 次或 1 次,等价于 {0,1}

例如:\d+ 表示匹配至少一个数字; ^app\w{0,2}$ 表示匹配以 app 开头的长度不超过 5 的字符串,包括 apple、apply 等。

限定符的匹配默认是贪婪(Greedy)的,即尽可能匹配更多的字符,但这种默认行为有时候并不是我们想要的。这时候可以使用非贪婪(Lazy)匹配,只需要在贪婪匹配的限定符后添加一个 ? 即可。

例如:fo{1,3}? 会匹配字符串 foooooo 中的 fo,而 fo{1,3} 则会匹配到 fooo,因为这是一个贪婪模式,会尽可能匹配更多的字符 o

其他元字符

  • | : 匹配两个模式之一
  • . : 匹配任何字符,除了换行符
  • () : 括号内部是一个匹配模式,表示一个组合,该组合匹配到的字符串将被捕获
  • (?: ) : 括号内部是一个匹配模式,表示一个组合,该组合匹配到的字符串不会被捕获
  • \ : 匹配一个特殊字符,类似于转义

例如:

  1. dog|t 表示匹配字符串 dog 或 t
  2. do(g|t) 表示匹配字符串 dog 或 dot;
  3. .* 表示匹配任意多个字符,不包括换行符
  4. \. 表示匹配字符 "." 本身

集合

如果需要匹配多个字符中的任何一个,一种解决办法是连续使用多个 | ,但更推荐的是使用集合。使用 [] 表示一个集合,其中包含需要匹配的若干字符。例如:[abcde] 表示匹配字母 a~e,等价于 (a|b|c|d|e) 。如果需要进行反向匹配,只需要在开头加上 ^ 符号,例如:[^abcde] 匹配任何字母 a~e 之外的字符。

  • [...] : 匹配集合中的任意字符
  • [^...] : 匹配集合外的任意字符

对于常见的集合,SAS 提供了更为简洁的表达方式:

  • [a-z] : 匹配小写字母 a~z
  • [A-Z] : 匹配大写字母 A~Z
  • [0-9] : 匹配数字 0~9
  • [[:alpha:]] : 匹配单个字母
  • [[:alnum:]] : 匹配单个字母或数字
  • [[:blank:]] : 匹配单个空白字符
  • [[:digit:]] : 匹配单个数字
  • [[:lower:]] : 匹配单个小写字母
  • [[:upper:]] : 匹配单个大写字母
  • [[:punct:]] : 匹配单个标点符号

例如:[A-Za-z_0-9_][A-Za-z0-9]{0,7} 可以匹配一个 SAS V5 下合法的变量名。

Tips: 更多正则表达式语法可查阅帮助文档:SAS 系统文档 > SAS 产品 > Base SAS > SAS® 9.4 Function and CALL Routines: Reference, Fifth Edition > Appendixes > Tables of Perl Regular Expression(PRX) Metacharacters

正则表达式的构建

通过构建合适的正则表达式,可以实现复杂规则的字符串的匹配和替换操作。下面通过一个实例,来理解正则表达式的完整构建过程。

创建包含若干文本型日期的数据集,其中某些日期是不完整的,使用 “uk” 进行替代:

data test;
    input dtc $10.;
cards;
2023-07-14
2003/07/UK
1999-07-uk
2015/UK/uk
1982-UK-17
ukuk-04-uK
ukuk/UK-uk
;
run;

现在,需要使用正则表达式对所有文本型日期进行模式匹配。观察数据,可以发现,这些文本型日期都有共同的规律,即按年、月、日的顺序呈现,使用 “-” 或 “/” 作为分隔符。

首先,使用 d{4}\d{2} 可以匹配完整的年、月、日;使用 (\/|\-) 可以匹配年、月、日之间的分隔符;因此,可以用以下正则表达式匹配一个完整的日期:

\d{4}(\/|\-)\d{2}(\/|\-)\d{2}

其次,部分不完整的日期使用“uk”替代,因此还需要额外使用 [Uu][Kk] 进行匹配,上述正则表达式进一步演变为:

(\d{4}|([Uu][Kk]){2})(\/|\-)(\d{2}|[Uu][Kk])(\/|\-)(\d{2}|[Uu][Kk])

最后,加上定界符,限制匹配的开头和结尾:

^(\d{4}|([Uu][Kk]){2})(\/|\-)(\d{2}|[Uu][Kk])(\/|\-)(\d{2}|[Uu][Kk])$

至此,一个用于匹配不完整文本型日期的正则表达式就构建完成了。

字符串匹配

正则表达式构建完成后,就可以应用于字符串的匹配。SAS 提供了 PRXMATCH 函数用于正则表达式的模式匹配。

我们可以在函数 PRXMATCH 中直接使用正则表达式,也可以先使用函数 PRXPARSE 对正则表达式进行解析,获得解析后的 ID,然后在函数 PRXMATCH 中使用这个 ID。

在 SAS 中,正则表达式本身也是一个字符串,为了不与普通字符串相混淆,需要在正则表达式两端添加斜杠 / 以示区分,以下为前一节中的正则表达式在匹配模式下的呈现形式:

/^(\d{4}|([Uu][Kk]){2})(\/|\-)(\d{2}|[Uu][Kk])(\/|\-)(\d{2}|[Uu][Kk])$/

完整 SAS 代码如下:

data match;
    set test;
    id = prxparse("/^(\d{4}|([Uu][Kk]){2})(\/|\-)(\d{2}|[Uu][Kk])(\/|\-)(\d{2}|[Uu][Kk])$/");
    if prxmatch(id, dtc) then do;
        flag = "匹配成功";
    end;
    else do;
        flag = "匹配失败";
    end;
run;

匹配结果:

img

字符串替换

除了使用正则表达式匹配字符串外,通常我们还希望能够实现字符串的替换。SAS 提供的 PRXCHANGE 函数可以帮助我们完成这一任务。

在 SAS 中,字符串的替换需要使用替换模式的正则表达式,我们需要在匹配模式的正则表达式开头添加字符 s,并在末尾追加替换结果的正则表达式。

例如:s/(\d{4})-(\d{2})-(\d{2})/$1$2$3/ 表示匹配 “YYYY-MM-DD” 的日期,并删除分隔符 “-”。其中 $1, $2, $3 表示对缓冲区字符串的引用,缓冲区的字符串是通过元字符 () 来捕获的,左半括号出现的位置代表了缓冲区的序号,即 $1 表示捕获年份 “YYYY” 的第一个缓冲区, $2 表示捕获月份 “MM” 的第二个缓冲区,以此类推。括号的捕获行为是默认的,如果仅仅是表示一个组合而不进行捕获,可以在括号内开头添加 ?:,代表不进行捕获,不会生成缓冲区的序号。

回到前面匹配不完整文本型日期的例子,现在,我们需要在匹配完成之后,将日期的展示格式统一修改为 “MM-DD-YYYY” 的形式。以下为这个例子中的正则表达式在替换模式下的呈现形式:

s/^(\d{4}|(?:[Uu][Kk]){2})(?:\/|\-)(\d{2}|[Uu][Kk])(?:\/|\-)(\d{2}|[Uu][Kk])$/$2-$3-$1/

完整 SAS 代码如下:

data replace;
    set test;
    id = prxparse("s/^(\d{4}|(?:[Uu][Kk]){2})(?:\/|\-)(\d{2}|[Uu][Kk])(?:\/|\-)(\d{2}|[Uu][Kk])$/$2-$3-$1/");
    dtc_new = prxchange(id, -1, dtc);
run;

替换结果:

img

其他函数和子程序

除了匹配和替换字符串之外,SAS 还提供了一些其他正则表达式相关的函数,例如:

  • PRXPOSN : 获取指定缓冲区字符串的函数
  • CALL PRXPOSN : PRXPOSN 的子程序版本
  • CALL PRXSUBSTR : 获取匹配指定模式的字符串位置和长度信息
  • CALL PRXNEXT : 循环迭代获取匹配指定模式的字符串
  • ...

相关函数和子程序的具体说明可查阅 SAS 帮助文档。

正则表达式的可视化

正则表达式虽然很强大,但通常被认为是易写难读的,在提高字符串处理效率的同时牺牲了部分可读性。一些可视化工具可以帮助我们更好地理解正则表达式,在构建正则表达式的时候提供些许辅助作用。

Jex.im

网址:https://jex.im/regulex/

这是一个 JavaScript 正则表达式(大部分语法也适用于 SAS)的可视化工具,将正则表达式拆解并以图形的方式进行呈现,可以帮助理解正则表达式的具体含义。

img

Runoob 在线测试工具

网址:https://c.runoob.com/front-end/854/

这是一个正则表达式在线测试工具,将正则表达式应用到待匹配文本中,并返回匹配结果,支持替换文本。

img

posted @ 2023-07-20 20:55  Snoopy1866  阅读(927)  评论(0编辑  收藏  举报