SAS:如何在字符串中找到一个字符/一组字符的第n个实例



我正试图找到一个函数来索引字符的第n个实例。

例如,如果我有字符串ABABABBABSSSDDEE,并且我想找到A的第三个实例,我该怎么做?如果我想找到AB 的第四个实例怎么办

ABABABBABSSSDDEE

data HAVE;
   input STRING $;
   datalines;
ABABABBASSSDDEE
;
RUN;

以下是使用SAS find()函数查找SAS字符串中一组字符的第N个实例的简化实现:

     data a;
        s='AB bhdf +BA s Ab fs ABC Nfm AB ';
        x='AB';
        n=3;
        /* from left to right */
        p = 0;
        do i=1 to n until(p=0); 
           p = find(s, x, p+1);
        end;
        put p=;
        /* from right to left */
        p = length(s) + 1;
        do i=1 to n until(p=0); 
           p = find(s, x, -p+1);
        end;
        put p=;
     run;

正如您所看到的,它同时允许从左到右和从右到左的搜索。

您可以将这两个组合成SAS用户定义函数(负n表示从右向左搜索,就像在查找函数中一样):

     proc fcmp outlib=sasuser.functions.findnth;
        function findnth(str $, sub $, n);
           p = ifn(n>=0,0,length(str)+1);
           do i=1 to abs(n) until(p=0);
              p = find(str,sub,sign(n)*p+1);
           end;
           return (p);
        endsub;
     run;

请注意,上面使用FIND()和FINNTH()函数的解决方案假设搜索到的子字符串可以与其上一个实例重叠。例如,如果我们在字符串"ABAAAA"中搜索子字符串"AAA",则"AAA"的第一个实例将在位置3中找到,第二个实例-在位置4中找到。也就是说,第一个实例和第二个实例是重叠的。因此,当我们找到一个实例时,我们将位置p增加1(p+1),以开始搜索的下一次迭代(实例)。然而,如果这种重叠在您的搜索中不是有效的情况,并且您希望在上一个子字符串实例结束后继续搜索,那么我们应该将p不是增加1,而是增加子字符串x的长度。这将加快我们的搜索速度(子字符串x越长),因为我们在遍历字符串s时将跳过更多的字符。在这种情况下,在我们的搜索代码中,我们应该将p+1替换为p+w,其中w=长度(x)。

在我最近的SAS博客文章《在字符串中查找子字符串的第n个实例》中描述了对这个问题的详细讨论。我还发现,使用find()函数比在SAS中使用正则表达式函数要快得多。

我意识到我来这里参加聚会迟到了,但为了增加答案,以下是我的想法。

DATA test;
   input   = "ABABABBABSSSDDEE";
   A_3  = find(prxchange("s/A/#/",   2, input), "A");
   AB_4 = find(prxchange("s/AB/##/", 3, input), "AB");
RUN;

细分来看,prxchange()只是做了一个模式匹配替换,但它的好处是你可以告诉它替换该模式多少次。因此,prxchange("s/A/#/", 2, input)input中的前两个A替换为#。一旦替换了前两个A,就可以将其封装在find()函数中,以找到"第一个A",它实际上是原始字符串的第三个A。

关于这种方法需要注意的一点是,理想情况下,替换字符串的长度应该与要替换的字符串的长度相同。例如,注意之间的差异

prxchange("s/AB/##/", 3, input) /* gives 8 (correct) */

prxchange("s/AB/#/", 3, input)  /* gives 5 (incorrect) */

这是因为我们已经用长度为1的字符串替换了三次长度为2的字符串。换句话说:

(length("#") - length("AB")) * 3 = -3

因此CCD_ 8。

希望这能帮助到外面的人!

data _null_;
findThis = 'A'; *** substring to find;
findIn = 'ADABAACABAAE'; **** the string to search;
instanceOf=1; *** and the instance of the substring we want to find;
pos = 0; 
len = 0; 
startHere = 1; 
endAt = length(findIn);
n = 0; *** count occurrences of the pattern;
pattern =  '/' || findThis || '/'; 
rx = prxparse(pattern);
CALL PRXNEXT(rx, startHere, endAt, findIn, pos, len);
if pos le 0 then do;
    put 'Could not find ' findThis ' in ' findIn;
end;
else do while (pos gt 0);
    n+1;
    if n eq instanceOf then leave;
    CALL PRXNEXT(rx, startHere, endAt, findIn, pos, len);
end;
if n eq instanceOf then do;
    put 'found ' instanceOf 'th instance of ' findThis ' at position ' pos ' in ' findIn;
end;
else do;
    put 'No ' instanceOf 'th instance of ' findThis ' found';
end;
run;

这里有一个使用find()函数和数据步骤中的do循环的解决方案。然后,我将该代码放入proc fcmp过程中,创建自己的函数find_n()。这将大大简化使用它的任何任务,并允许代码重用。

定义数据:

data have;  
  length string $50;
  input string $;
  datalines;
ABABABBABSSSDDEE
;
run;

Do循环解决方案:

data want;
  set have;  
  search_term = 'AB';
  nth_time = 4;
  counter = 0;
  last_find = 0;
  start = 1;
  pos = find(string,search_term,'',start);
  do while (pos gt 0 and nth_time gt counter);
    last_find = pos;
    start = pos + 1;
    counter = counter + 1;
    pos = find(string,search_term,'',start+1);
  end;
  if nth_time eq counter then do;    
    put "The nth occurrence was found at position " last_find;
  end;
  else do;
    put "Could not find the nth occurrence";
  end;
run;

定义proc fcmp函数:

注意:如果找不到第n次出现,则返回0。

options cmplib=work.temp.temp;
proc fcmp outlib=work.temp.temp;
  function find_n(string $, search_term $, nth_time) ;    
    counter = 0;
    last_find = 0;
    start = 1;
    pos = find(string,search_term,'',start);
    do while (pos gt 0 and nth_time gt counter);
      last_find = pos;
      start = pos + 1;
      counter = counter + 1;
      pos = find(string,search_term,'',start+1);
    end;
    result = ifn(nth_time eq counter, last_find, 0);
    return (result);
  endsub;
run;

示例proc fcmp用法:

请注意,这会调用函数两次。第一个示例显示了原始请求解决方案。第二个示例显示了当找不到匹配项时会发生什么。

data want;
  set have;  
  nth_position = find_n(string, "AB", 4);
  put nth_position =;
  nth_position = find_n(string, "AB", 5);
  put nth_position =;
run;

最新更新