2015-10-13 2 views
3

При вызове функции CATT() с помощью% sysfunc существует ли способ остановить ее от оценки выражения?Как предотвратить функции CATx от оценки выражения

В приведенном примере код:

%let date=10-13-2015; 
%put %sysfunc(catt(The date Is:,&date)); 

Я хотел бы, чтобы вернуться:

The date Is:10-13-2015 

Поскольку 10-13-2015 просто текстовая строка. Но вместо того, чтобы CATT() видит дефис, как знак вычитания и оценивает его как числовое выражение, возвращая:

The date Is:-2018 

Я попытался макрос процитировать, но ничего не изменится, я полагаю, потому что мне нужно как-то скрыть значения из CATT(). Кажется, что если какой-либо аргумент CATT выглядит как выражение, он будет рассматриваться как таковой.

Другой пример:

%let value=2 and 3; 
%put %sysfunc(catt(The value Is:,&value)); 
The value Is:1 
+0

Вау, хороший вопрос ... это тяжелый вопрос. –

ответ

1

При условии, что вы можете сделать это, просто удалить запятую - нет никакой необходимости, чтобы отделить его в отдельный параметр (если вы не используете catx(), а не catt():

%let date=10-13-2015; 
%put %sysfunc(catt(The date Is: &date)); 

Лично я считаю, что лучший способ работы - сохранить дату как значение даты SAS, а затем использовать второй (необязательный) параметр %sysfunc для применения форматирования. Это обеспечивает лучшую гибкость.

%let date = %sysfunc(mdy(10,13,2015)); 
%put The date Is: %sysfunc(sum(&date),mmddyyd10.); 

Если вы настойчивы на оригинальном подходе и использовании catx(), то я не знаю, как это сделать точно. Самое близкое, что я мог получить, это вставить фрагмент текста, чтобы он не мог интерпретироваться как выражение, а затем удалять этот текст после использования tranwrd. Довольно, некрасиво, и это оставляет пространство:

%let date=10-13-2015; 
%let tmp=%sysfunc(catx(#, The date Is: , UNIQUE_STRING_TO_REMOVE&date)); 
%let want=%sysfunc(tranwrd(&tmp, UNIQUE_STRING_TO_REMOVE,)); 

%put &want; 

Выдает:

The date Is:# 10-13-2015 

Я также попробовал все комбинации макро цитировал, и просмотрел весь список функций SAS и не мог видеть любой другой жизнеспособные варианты.

+0

Спасибо @Robert. Да, вы правильно догадались, что мой настоящий код - CATX(). И мой настоящий код не является датой (я согласен, что это не способ обработки дат, просто показался самым простым примером). Я, вероятно, возьму ваш подход к добавлению и удалению строки или просто избегаю CATX(). Это интересная проблема. Полагаю, что это частично побочный эффект CATX, который рад иметь дело с числовыми аргументами. И, конечно, только проблема с вызовами% SYSFUNC, так как нет хорошего способа сказать «Это значение является строкой». – Quentin

1

Проблема с% SYSFUNC(), оценивающая аргументы, не ограничена рядом функций CAT(). Любая функция, которая принимает числовые значения, приведет к попытке SAS оценить предоставленное выражение.

Это может быть полезной функцией. Например:

%let start_dt=10OCT2012 ; 
%put %sysfunc(putn("&start_dt"d +1,date9)); 

Вам не нужно использовать функции CAT() для работы с макропеременными. Просто увеличьте значения рядом друг с другом, а «объединены».

%let date=10-13-2015; 
%put The date Is:&date; 

Если вы хотите создать макрос, который работает как функция CATX(), то это также не сложно.

%macro catx /parmbuff ; 
%local dlm return i ; 
%if %length(&syspbuff) > 2 %then %do; 
    %let syspbuff = %qsubstr(&syspbuff,2,%length(&syspbuff)-2); 
    %let dlm=%qscan(&syspbuff,1,%str(,),q); 
    %let return=%qscan(&syspbuff,2,%str(,),q); 
    %do i=3 %to %sysfunc(countw(&syspbuff,%str(,),q)); 
    %let return=&return.&dlm.%qscan(&syspbuff,&i,%str(,),q); 
    %end; 
%end; 
&return. 
%mend catx; 

%put %catx(|,a,b,c); 
a|b|c 
%put "%catx(",",a,b,c,d)"; 
"a","b","c","d" 
+0

Понял, @Tom, но это упрощенный пример. В реальной настройке я надеялся использовать CATX() в настройке макроса и наткнулся на этот сюрприз (по крайней мере для меня), что он будет оценивать элементы в списке, которые выглядят как выражения. – Quentin

+0

Это проблема% SYSFUNC(), а не только функций CAT(). – Tom

+0

Я думаю, что это больше CAT(). То есть CAT() решает, что значение является выражением и оценивает его. UPCASE() нет. Сравнить:% put% sysfunc (upcase (1 или 0)); % put% sysfunc (catt (1 или 0)); Я думаю, что это гибкость CAT, довольная символьными или числовыми аргументами и выражениями, что вызывает эту проблему при настройке макроса. На языке шагов DATA можно просто добавить кавычки, чтобы указать, что это строка. – Quentin

1

Я, к сожалению, не вижу легкого пути вокруг этого.Я вижу, что вы могли бы теоретически передать это через функцию FCMP, хотя с FCMP не позволяет аргументы истинных переменных, то есть далеко не идеально, но ...

proc fcmp outlib=work.funcs.funcs; 
    function catme(delim $, in_string $) $; 
    length _result $1024; 
    length _new_delim $1; 
    _new_delim = scan(in_string,1,delim); 
    do _i = 1 to countc(in_string,delim); 
     _result = catx(_new_delim, _result, scan(in_string,_i+1,delim)); 
    end; 
    return(_result); 
    endfunc; 
quit; 

options cmplib=work.funcs; 

%let date=10-13-2015; 
%put %sysfunc(catme(|,:|The date Is| &date.)); 

Или добавить кавычки в аргументе а затем удалите их после CATx.

%sysfunc(dequote(%sysfunc(catt(.... ,"&date.")))) 

Все беспорядочно.

+0

Мне нравится это решение. По крайней мере, беспорядок скрыт. =) –

+0

Возможно, способ, которым передаются параметры, может быть улучшен? Предполагая, что @Quentin хочет функцию 'catx()', сохраните первый параметр как строку, используемую в качестве разделителя, и просто '% bquote' второй параметр (при вызове), который позволит вам использовать список, разделенный запятыми значения? –

+0

Я думаю, что если '% bquote' работал так, это также сработало бы для оригинального' catx', к сожалению. – Joe

0

Чуть менее безумный макро функция стиль без dosubl:

%macro catx() /parmbuff; 
%local rc dlm i params OUTSTR QWORD outstr; 
%let SYSPBUFF = %qsubstr(&SYSPBUFF,2,%length(&SYSPBUFF)-2); 
%let dlm = %qscan(&SYSPBUFF,1,%str(,)); 
%let params = %qsubstr(&SYSPBUFF,%index(&SYSPBUFF,%str(,))+1); 

%let i = 1; 
%let QWORD = %scan(&PARAMS,&i,%str(,)); 
%let OUTSTR = &QWORD; 
%do %while(&QWORD ne); 
    %let i = %eval(&i + 1); 
    %let QWORD = %scan(&PARAMS,&i,%str(,)); 
    %if &QWORD ne %then %let OUTSTR = &OUTSTR.&DLM.&QWORD; 
%end; 

%unquote(&OUTSTR) 
%mend catx; 

%put %catx(%str(),abc,10 - 1 + 2,def); 

Несколько более безумный, но, по-видимому работает вариант - использовать %sysfunc(dosubl(...)) и много макро логики создать макрос функции в стиле, который принимает входной сигнал в том же как %sysfunc(catx(...)), но заставляет catx обрабатывать весь ввод как текст, цитируя его и вызывая его на шаге данных.

%macro catxt() /parmbuff; 
%local rc dlm i params QPARAMS QWORD outstr; 
%let SYSPBUFF = %qsubstr(&SYSPBUFF,2,%length(&SYSPBUFF)-2); 
%let dlm = %qscan(&SYSPBUFF,1,%str(,)); 
%let params = %qsubstr(&SYSPBUFF,%index(&SYSPBUFF,%str(,))+1); 

%let i = 1; 
%let QWORD = "%scan(&PARAMS,&i,%str(,))"; 
%let QPARAMS = &QWORD; 
%do %while(&QWORD ne ""); 
    %let i = %eval(&i + 1); 
    %let QWORD = "%scan(&PARAMS,&i,%str(,))"; 
    %if &QWORD ne "" %then %let QPARAMS = &QPARAMS,&QWORD; 
%end; 

%let rc = %sysfunc(dosubl(%str(
    data _null_; 
     call symput("OUTSTR",catx("&dlm",%unquote(&QPARAMS))); 
    run; 
))); 

&OUTSTR 
%mend catxt; 

%put %catxt(%str(),abc,10 - 1 + 2,def); 

Хотя это использует шаг данных для выполнения catx, dosubl позволяет все это будет работать в любом месте, где можно было нормально использовать %sysfunc(catx(...)).

+0

Ах, некоторые волшебные функции макроса DOSUBL! Прекрасный подход. Я все еще избегаю DOSUBL в производстве, из-за странной ошибки столкновения. Обратите внимание, если вы добавите '% let outstr = Hi Mom;' в открытый код перед вызовом макроса, макрос вернет Hi Mom. Несмотря на то, что вы соответствующим образом объявили OUTSTR локальным для вашего макроса.Но это говорит о том, что в DOSUBL есть много обещаний для такого подхода, поэтому, надеюсь, они смогут исправить эту ошибку в ближайшее время. :) – Quentin

+0

Если вы хотите создать версию макроса CATX(), не нужно использовать 'dosubl' или'% sysfunc (catx()) '. – Tom

+0

@ Тому, что произошло со мной, но только после факта. Я мог бы еще раз пойти. – user667489