Проблема цитирования SAS MACRO: передача строки с триггером макроса в качестве параметра макроса

Можно ли передать строку с триггером макроса в качестве параметра макроса? См. приведенный ниже пример кода:

options mprint;
%let string5='%abc%def%';
%macro test(string);
data _null_;
    call execute('%test2('||&string.||')');
run;
%mend;

%macro test2(string2);
    data test3;
        a=%str(%')&string2.%str(%');
    run;
%mend;

%test(&string5);

Этот код выполнился успешно, но попытался вызвать макрос %abc и %def, что привело к появлению предупреждений.

Если я попытался поместить его в кавычки, чтобы замаскировать строку, это дало синтаксическую ошибку, как показано ниже:

options mprint;

    %let string5='%abc%def%';
    %macro test(string);

    data _null_;
        call execute('%test2('||%superQ(string)||')');
    run;
    %mend;

    %macro test2(string2);
        data test3;
            a=%str(%')&string2.%str(%');
        run;
    %mend;

    %test(&string5);

ERROR 22-322: Syntax error, expecting one of the following: a name, a quoted string, a numeric constant, a datetime constant, a missing value, arrayname, (, +, -, INPUT, NOT, PUT, ^, _NEW_, ~.  

Есть ли способ исправить это без предупреждений? Заранее спасибо!


person Steve Z.    schedule 20.04.2017    source источник
comment
Что вы на самом деле пытаетесь сделать здесь? Вполне может быть более простой способ сделать это.   -  person user667489    schedule 20.04.2017
comment
Я пытаюсь передать подобный шаблон в качестве параметра, который содержит%. То, что я делаю здесь, это просто пример.   -  person Steve Z.    schedule 20.04.2017
comment
Использование %nrstr() очень полезно при вызове макросов через CALL EXECUTE, но я не уверен, имеет ли это значение для вашей проблемы. call execute(cats('%nrstr(%test2)(',symget('string'),')');   -  person Tom    schedule 20.04.2017


Ответы (4)


Попробуй это:

%let string5='%abc%def%';
%macro test(string);
data _null_;
    call execute('%test2('||%nrstr("&string.")||')');
run;
%mend;

%macro test2(string2);
    data test3;
        a=%nrquote(&string2.);
    run;
%mend;

%test(&string5);
person Shenglin Chen    schedule 20.04.2017
comment
Оно работает! Большое спасибо. Что меня беспокоит, так это то, что %nrstr может принимать только постоянный текст и не разрешает никакие макросы, но это не так, если постоянный текст заключен в двойные кавычки. - person Steve Z.; 21.04.2017
comment
Исправление, вы маскируете его во время компиляции, но позволяете разрешить его на этапе выполнения. Это решит проблему. - person Steve Z.; 21.04.2017

Обычно в макросе достаточно просто защититься от спецсимволов. Например, вы можете использовать функцию %superq(), чтобы заключить в кавычки значение существующей макропеременной.

where name like %unquote(%str(%')%superq(parm1)%str(%'))

Или используйте функцию symget() в шаге данных, чтобы получить значение без необходимости развертывания макроса.

pattern = quote(symget('parm1'),"'");

Но самое сложное — это вызов макроса. Вам нужно защитить персонажей, чтобы запустить вызов макроса. Вы можете использовать аналогичные функции в вызове макроса.

Одна полезная вещь — поручить пользователям передавать значение параметра в виде строки в кавычках, а затем в коде макроса вы можете удалить кавычки, когда они не нужны.

%macro mymacro(parm1=);
  %let parm1=%qsysfunc(dequote(&parm1));
  ...
%mend;
%mymacro(parm1='fred%')

Или вы можете попросить их передать значение по имени.

%macro mymacro(mvar=);
  %local pattern ;
  %let pattern=%superq(&mvar);
  ...
%mend ;

%let my_pattern=%qsysfunc(dequote('fred%'));
%mymacro(mvar=my_pattern)
person Tom    schedule 20.04.2017

Если это уже работает так, как вы хотите, и вы просто хотите подавить это одно предупреждающее сообщение, вы можете рассмотреть возможность установки option nomerror; перед запуском рассматриваемого раздела кода, а затем снова установить его обратно.

person user667489    schedule 20.04.2017
comment
Спасибо, но я бы не предпочел этого, так как не могу предвидеть другие предупреждения. - person Steve Z.; 21.04.2017

Просто обновите окончательное решение, которое я выберу. Я отказался от способа передачи параметров макроса между разными макросами, вместо этого я передал имя переменной макроса в виде строки. Примеры кодов приведены ниже:

options mprint;
%let string5='%abc%def%';

%macro test(string);
data _null_;
    call execute('%test2('||&string.||')');
run;
%mend;

%macro test2(string2);
    data test3;
        a=&&&string2.;
    run;
%mend;

%test('string5');
person Steve Z.    schedule 21.04.2017