You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需修改输入数据,如何使用SAS的CARDS语句创建目标表格?

无需修改原始输入的SAS CARDS数据集生成方案

问题背景

需要基于以下未对齐的原始输入数据,用SAS的CARDS语句生成数据集,但不想修改原始数据(当前可行方法是给输入数据添加空格对齐变量位置,才能通过列输入正确读取)。

原始输入数据

la grande vadrouille Louis de Funès 16 1966 A V 7
le mur de l’atlantique Jean Poiret 14 1970 AB 6
le cercle rouge Alain Delon 20 1970 Z A 8
le corniaud Louis de Funès 14 1965 SD 4
le chanteur de mexico Luis Mariano 12 1956 A B 5
la traversée de Paris Jean Gabin 19 1958 S 2

当前需修改输入的可行代码

DATA DMExo1.Q1;
INPUT Film  $CHAR22. Acteur $15. Note 39-40 Annee 41-45 Code $ 46-49 Ordre ;
CARDS;
la grande vadrouille   Louis de Funès 16 1966 A V 7
le mur de l’atlantique Jean Poiret    14 1970 AB  6
le cercle rouge        Alain Delon    20 1970 Z A 8
le corniaud            Louis de Funès 14 1965 SD  4
le chanteur de mexico  Luis Mariano   12 1956 A B 5
la traversée de Paris  Jean Gabin     19 1958 S   2
;RUN;

解决方案:正则表达式匹配提取

利用SAS的正则表达式功能,直接从原始未对齐的行中匹配提取各变量,无需修改输入数据。核心思路是通过正则表达式识别行内各部分的结构(电影名、演员名、数字字段、代码字段),精准提取对应内容。

实现代码

DATA DMExo1.Q1;
    length Film $22 Acteur $15 Note 8 Annee 4 Code $5 Ordre 8;
    infile cards truncover;
    input @; /* 读取整行但不移动输入指针 */
    /* 编译正则表达式,匹配行内各字段结构 */
    regex = prxparse('/^(.+?) (\w+(?: \w+)*) (\d+) (\d+) (.+) (\d+)$/');
    if prxmatch(regex, _infile_) then do;
        Film = prxposn(regex, 1, _infile_);       /* 提取电影名 */
        Acteur = prxposn(regex, 2, _infile_);     /* 提取演员名 */
        Note = input(prxposn(regex, 3, _infile_), 8.); /* 提取评分,转为数值型 */
        Annee = input(prxposn(regex, 4, _infile_), 4.); /* 提取年份,转为数值型 */
        Code = prxposn(regex, 5, _infile_);       /* 提取代码 */
        Ordre = input(prxposn(regex, 6, _infile_), 8.); /* 提取序号,转为数值型 */
    end;
    drop regex; /* 删除临时变量 */
CARDS;
la grande vadrouille Louis de Funès 16 1966 A V 7
le mur de l’atlantique Jean Poiret 14 1970 AB 6
le cercle rouge Alain Delon 20 1970 Z A 8
le corniaud Louis de Funès 14 1965 SD 4
le chanteur de mexico Luis Mariano 12 1956 A B 5
la traversée de Paris Jean Gabin 19 1958 S 2
;
RUN;

代码说明

  • input @;:读取整行内容到_INFILE_变量中,且不移动输入指针,方便后续处理整行数据。
  • 正则表达式/^(.+?) (\w+(?: \w+)*) (\d+) (\d+) (.+) (\d+)$/:
    • ^(.+?):非贪婪匹配电影名(匹配到演员名前的所有内容)
    • (\w+(?: \w+)*):匹配演员名(支持带空格的姓名)
    • (\d+):匹配评分(Note)和年份(Annee)的数字字段
    • (.+):匹配代码字段(支持带空格的代码)
    • (\d+)$:匹配最后一个数字序号(Ordre)
  • prxposn:从匹配结果中提取对应分组的内容,再通过input函数将数字类字段转为数值型。

替代方案:从后往前拆分字段

如果对正则不熟悉,也可以通过统计行内字段数量,从后往前拆分固定位置的数字字段,再处理前面的字符字段:

DATA DMExo1.Q1;
    length Film $22 Acteur $15 Note 8 Annee 4 Code $5 Ordre 8;
    array temp_fields[20] $30 _temporary_; /* 临时数组存储拆分后的所有字段 */
    infile cards truncover;
    input @;
    field_count = countw(_infile_, ' '); /* 统计当前行的字段总数 */
    /* 将整行拆分为单个字段存入临时数组 */
    do i = 1 to field_count;
        temp_fields[i] = scan(_infile_, i, ' ');
    end;
    /* 提取末尾固定位置的数值字段 */
    Ordre = input(temp_fields[field_count], 8.);
    Annee = input(temp_fields[field_count-2], 4.);
    Note = input(temp_fields[field_count-3], 8.);
    /* 根据字段总数提取代码字段 */
    if field_count = 11 then Code = catx(' ', temp_fields[9], temp_fields[10]);
    else if field_count = 10 then Code = temp_fields[9];
    else if field_count = 9 then Code = temp_fields[8];
    /* 合并前面的字段为电影名+演员名,需手动拆分(已知分界的情况) */
    Film = catx(' ', temp_fields[1], temp_fields[2], temp_fields[3]);
    Acteur = catx(' ', temp_fields[4], temp_fields[5], temp_fields[6]);
    /* 需根据每行电影名的字段数调整,示例仅适配第一行,通用场景建议用正则方案 */
    drop field_count i temp_fields:;
CARDS;
la grande vadrouille Louis de Funès 16 1966 A V 7
le mur de l’atlantique Jean Poiret 14 1970 AB 6
le cercle rouge Alain Delon 20 1970 Z A 8
le corniaud Louis de Funès 14 1965 SD 4
le chanteur de mexico Luis Mariano 12 1956 A B 5
la traversée de Paris Jean Gabin 19 1958 S 2
;
RUN;

注意:此方案需要明确电影名和演员名的字段分界,否则拆分结果可能不准确,因此正则方案更通用。

内容的提问来源于stack exchange,提问作者goupi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:24:57