SAS使用prxchange或prxpson(prxmatch(prxparse()))从字符串中提取子字符串

时间:2020-06-10 06:03:30

标签: regex sas substring

底部发布的2个解决方案

我的代码

    data test;  
        extract_string = "<some string here>";
        my_result1 = prxchange(cat("s/^.*", extract_string, ".*$/$1/"), -1, "A1M_PRE");  
        my_result2 = prxchange(cat("s/^.*", extract_string, ".*$/$1/"), -1, "AC2_0M");  
        my_result3 = prxchange(cat("s/^.*", extract_string, ".*$/$1/"), -1, "GA3_30M");
        my_result4 = prxchange(cat("s/^.*", extract_string, ".*$/$1/"), -1, "DE3_1H30M");  
    run;

所需结果

在末尾有_的字符串中,提取M之后但M之前的数字。结果集应为:

    my_result1 = ""  
    my_result2 = "0"  
    my_result3 = "30"  
    my_result4 = "30"

以下extract_string值失败

"\.*(\d*)M\b\"  
"\.*(\d*?)M\b\"  
"\.*(\d{*})M\b\"  
"\.*(\d{*?})M\b\"  
"\.*(\d){*}M\b\"  
"\.*(\d){*?}M\b\"  

"\.*(\d+)M\b\"  
"\.*(\d+?)M\b\"  
"\.*(\d{+})M\b\"  
"\.*(\d{+?})M\b\"  
"\.*(\d){+}M\b\"  
"\.*(\d){+?}M\b\"  

"\.*(\d+\d+)M\b\" 

可能需要帮助的潜在解决方案

  • 也许我还没有测试正确的extract_string。有想法吗?
  • 也许我的cat("s/&.*", extract_string, ".*$/$1/")需要修改。有想法吗?
  • 也许我需要使用prxpson(prxmatch(prxparse()))而不是prxchange。该如何制定?

我查看过但无法成功实现的链接

https://support.sas.com/rnd/base/datastep/perl_regexp/regexp-tip-sheet.pdf

https://www.pharmasug.org/proceedings/2013/CC/PharmaSUG-2013-CC35.pdf

SAS PRX to extract substring please

extracting substring using regex in sas

Extract substring from a string in SAS

解决方案

解决方案1 ​​

cat函数的后缀和extract_string被修改。

    data test;  
        extract_string = "?(?:_[^_r\n]*?(\d+)M)?$";
        my_result1 = prxchange(cat("s/^.*", extract_string, "/$1/"), -1, "A1M_PRE");
        my_result2 = prxchange(cat("s/^.*", extract_string, "/$1/"), -1, "AC2_0M");
        my_result3 = prxchange(cat("s/^.*", extract_string, "/$1/"), -1, "GA3_30M");
        my_result4 = prxchange(cat("s/^.*", extract_string, "/$1/"), -1, "DE3_1H30M");
    run;

解决方案2

此解决方案使用其他prx系列功能:prxparseprxmatchprxposn

data have;
  length string $10;
  input string;
  datalines;
A1M_PRE
AC2_0M
GA3_30M
DE3_1H30M
;

data want;
  set have;

  rxid = prxparse ('/_.*?(\d+)M\s*$/');

  length digit_string $8;

  if prxmatch (rxid, string) then digit_string = prxposn(rxid,1,string);

  number_extracted = input (digit_string, ? 12.);
run;

3 个答案:

答案 0 :(得分:3)

我知道SAS可以使用Perl的正则表达式引擎。后者支持\K,它指示引擎丢弃到目前为止匹配的所有内容,并将匹配的起点重置为当前位置。因此,以下正则表达式应与您感兴趣的子字符串的数字匹配。

_.*?\K\d+(?=M$)

Demo

不匹配将被解释为已匹配的空字符串。

答案 1 :(得分:2)

如果要从行中删除并在行的末尾保留M之前的数字,则可以使用捕获组。在替换中,保留组1 $1

的值
^.*?(?:_[^_r\n]*?(\d+)M)?$

说明

  • ^字符串的开头
  • .*?尽可能匹配任何字符
  • (?:非捕获组
    • _[^_r\n]*?匹配_和除下划线以外的所有字符
    • (\d+)M捕获组1 ,匹配1个以上的数字,后跟M
  • )?关闭组并将其设置为可选
  • $字符串结尾

Regex demo


您可以将extract_string设置为完整模式:

extract_string = "^.*?(?:_[^_r\n]*?(\d+)M)?$";
my_result1 = prxchange(cat("s/", extract_string, "/$1/"), -1, "A1M_PRE");

或者如果您必须保持领先的^.*使用方式

extract_string = "?(?:_[^_r\n]*?(\d+)M)?$";

答案 2 :(得分:1)

使用PRXPOSN提取匹配组。

示例:

使用模式/_.*?(\d+)M\s*$/来查找最后一个M字符之前的数字。

正则表达式:

  • _文字下划线
  • .*?不贪婪任何字符
  • (\d+)捕获一个或多个数字
  • M文字M
  • \s*$-任意数量的尾随空格,因为SAS字符值用属性长度可变的空格正确填充了
data have;
  length string $10;
  input string;
  datalines;
A1M_PRE
AC2_0M
GA3_30M
DE3_1H30M
;

data want;
  set have;

  rxid = prxparse ('/_.*?(\d+)M\s*$/');

  length digit_string $8;

  if prxmatch (rxid, string) then digit_string = prxposn(rxid,1,string);

  number_extracted = input (digit_string, ? 12.);
run;

结果

enter image description here