如何在SAS中识别空格分隔值的正则模式并拆分至多列
SAS多值字段按指定正则模式拆分解决方案
现有数据集
1. hogwarts数据集
生成代码:
DATA hogwarts; INFILE DATALINES delimiter="," dsd; LENGTH Index Wizards $ 255; INPUT Index Wizards $ Points; DATALINES; 1,'Harry Potter Ron Weasley',100 2,'Hermione Granger Harry Potter',200 3,'Ron Weasley',300 ; RUN;
数据集结构:
| Index | Wizards | Points |
|---|---|---|
| 1 | Harry Potter Ron Weasley | 100 |
| 2 | Hermione Granger Harry Potter | 200 |
| 3 | Ron Weasley | 300 |
2. wizards数据集
生成代码:
DATA wizards; INPUT Name $64.; DATALINES; Harry Potter Ron Weasley Hermione Granger ; RUN;
数据集结构:
| Name |
|---|
| Harry Potter |
| Ron Weasley |
| Hermione Granger |
需求说明
匹配wizards数据集中的姓名模式,将hogwarts的Wizards列内容按出现位置拆分,生成Wizard1、Wizard2……WizardN列,输出数据集want结构如下:
| Index | Wizards | Points | Wizard1 | Wizard2 |
|---|---|---|---|---|
| 1 | Harry Potter Ron Weasley | 100 | Harry Potter | Ron Weasley |
| 2 | Hermione Granger Harry Potter | 200 | Hermione Granger | Harry Potter |
| 3 | Ron Weasley | 300 | Ron Weasley | . |
核心要求:
- 拆分结果严格保留原内容中的出现顺序
- 支持匹配单/多词组合的姓名模式
- 兼容
Wizards列中数量不固定的分隔空格 - 根据实际匹配结果自动调整
WizardN列的数量
实现方案
步骤1:生成正则匹配模板
从wizards数据集提取所有姓名,拼接成可精准匹配完整姓名的正则模式:
DATA _null_; SET wizards END=last; RETAIN regex_pattern; /* 拼接姓名为正则选择分支,添加引号避免部分匹配 */ regex_pattern = catx('|', regex_pattern, quote(trim(Name), "'")); IF last THEN DO; regex_pattern = cats('(', regex_pattern, ')'); CALL SYMPUT('regex', regex_pattern); END; RUN;
步骤2:统计最大所需列数
遍历hogwarts数据集,统计每行匹配到的姓名数量,确定需要生成的WizardN列的最大数量:
DATA _max_count; SET hogwarts NOBS=_nobs; /* 统计当前行匹配到的姓名总数 */ count = prxmatch(cats('/\s*®ex\s*/', 'g'), Wizards); RETAIN max_count; max_count = max(max_count, count); IF _n_ = _nobs THEN CALL SYMPUT('max_col', PUT(max_count, 8.)); STOP; RUN;
步骤3:动态拆分并填充列
利用数组动态生成WizardN列,循环提取匹配的姓名并填充:
DATA want; SET hogwarts; /* 根据最大列数定义数组 */ ARRAY Wizard[&max_col] $64.; LENGTH temp_str $255; temp_str = Wizards; DO i = 1 TO dim(Wizard); /* 提取当前字符串中第一个匹配的姓名 */ Wizard[i] = prxposn(prxparse(cats('/\s*(®ex)\s*/')), 1, temp_str); /* 移除已提取的姓名,压缩多余空格 */ IF NOT missing(Wizard[i]) THEN DO; temp_str = prxchange(cats('s/\s*', quote(trim(Wizard[i]), "'"), '\s*/ /'), 1, temp_str); temp_str = strip(compress(temp_str, , 's')); END; END; DROP i temp_str; RUN;
代码说明
- 正则模板:将所有姓名拼接为
(姓名1|姓名2|姓名3)的形式,确保只匹配完整姓名,避免出现部分字符匹配的错误。 - 动态列数:先统计最大匹配数量,保证生成的数组能覆盖所有行的拆分需求。
- 顺序提取:每次提取当前字符串中第一个匹配的姓名,移除后继续处理剩余内容,严格保留原位置顺序。
内容的提问来源于stack exchange,提问作者askadum
相关产品推荐
相关产品推荐

