diff --git a/all.sas b/all.sas index c8dcc6b..3465b9c 100644 --- a/all.sas +++ b/all.sas @@ -5092,6 +5092,59 @@ create table &outds (rename=( run; %mend mp_getmaxvarlengths;/** + @file + @brief Performs a text substitution on a file + @details Makes use of the GSUB function in LUA to perform a text substitution + in a file - either in-place, or writing to a new location. The benefit of + using LUA is that the entire file can be loaded into a single variable, + thereby side stepping the 32767 character limit in a data step. + + Usage: + + %let file=%sysfunc(pathname(work))/file.txt; + %let str=replace/me; + %let rep=with/this; + data _null_; + file "&file"; + put "&str"; + run; + %mp_gsubfile(file=&file, pattern=str, replacement=rep) + data _null_; + infile "&file"; + input; + list; + run; + + @param file= (0) The file to perform the substitution on + @param patternvar= A macro variable containing the Lua + [pattern](https://www.lua.org/pil/20.2.html) to search for. Due to the use + of special (magic) characters in Lua patterns, it is safer to pass the NAME + of the macro variable containing the string, rather than the value itself. + @param replacevar= The name of the macro variable containing the replacement + _string_. + @param outfile= (0) The file to write the output to. If zero, then the file + is overwritten in-place. + +

SAS Macros

+ @li ml_gsubfile.sas + +

Related Macros

+ @li mp_gsubfile.test.sas + + @version 9.4 + @author Allan Bowe +**/ + +%macro mp_gsubfile(file=0, + patternvar=, + replacevar=, + outfile=0 +)/*/STORE SOURCE*/; + + %ml_gsubfile() + +%mend mp_gsubfile; +/** @file mp_guesspk.sas @brief Guess the primary key of a table @details Tries to guess the primary key of a table based on the following logic: @@ -7571,6 +7624,7 @@ alter table &libds modify &var char(&len);

SAS Macros

@li mf_getplatform.sas + @li mf_getuniquefileref.sas **/ @@ -18749,6 +18803,50 @@ filename &fref1 clear; %end; %mend mv_webout; +/** + @file ml_gsubfile.sas + @brief Compiles the gsubfile.lua lua file + @details Writes gsubfile.lua to the work directory + and then includes it. + Usage: + + %ml_gsubfile() + +**/ + +%macro ml_gsubfile(); +data _null_; + file "%sysfunc(pathname(work))/ml_gsubfile.lua"; + put 'local fpath, outpath, file, fcontent '; + put ' '; + put '-- configure in / out paths '; + put 'fpath = sas.symget("file") '; + put 'outpath = sas.symget("outfile") '; + put 'if ( outpath == 0 ) '; + put 'then '; + put ' outpath=fpath '; + put 'end '; + put ' '; + put '-- open file and perform the substitution '; + put 'file = io.open(fpath,"r") '; + put 'fcontent = file:read() '; + put 'file:close() '; + put 'fcontent = string.gsub( '; + put ' fcontent, '; + put ' sas.symget(sas.symget("patternvar")), '; + put ' sas.symget(sas.symget("replacevar")) '; + put ') '; + put ' '; + put '-- write the file back out '; + put 'file = io.open(outpath, "w+") '; + put 'io.output(file) '; + put 'io.write(fcontent) '; + put 'io.close(file) '; +run; + +%inc "%sysfunc(pathname(work))/ml_gsubfile.lua"; + +%mend ml_gsubfile; /** @file ml_json.sas @brief Compiles the json.lua lua file diff --git a/base/mp_gsubfile.sas b/base/mp_gsubfile.sas new file mode 100644 index 0000000..e3a0478 --- /dev/null +++ b/base/mp_gsubfile.sas @@ -0,0 +1,53 @@ +/** + @file + @brief Performs a text substitution on a file + @details Makes use of the GSUB function in LUA to perform a text substitution + in a file - either in-place, or writing to a new location. The benefit of + using LUA is that the entire file can be loaded into a single variable, + thereby side stepping the 32767 character limit in a data step. + + Usage: + + %let file=%sysfunc(pathname(work))/file.txt; + %let str=replace/me; + %let rep=with/this; + data _null_; + file "&file"; + put "&str"; + run; + %mp_gsubfile(file=&file, pattern=str, replacement=rep) + data _null_; + infile "&file"; + input; + list; + run; + + @param file= (0) The file to perform the substitution on + @param patternvar= A macro variable containing the Lua + [pattern](https://www.lua.org/pil/20.2.html) to search for. Due to the use + of special (magic) characters in Lua patterns, it is safer to pass the NAME + of the macro variable containing the string, rather than the value itself. + @param replacevar= The name of the macro variable containing the replacement + _string_. + @param outfile= (0) The file to write the output to. If zero, then the file + is overwritten in-place. + +

SAS Macros

+ @li ml_gsubfile.sas + +

Related Macros

+ @li mp_gsubfile.test.sas + + @version 9.4 + @author Allan Bowe +**/ + +%macro mp_gsubfile(file=0, + patternvar=, + replacevar=, + outfile=0 +)/*/STORE SOURCE*/; + + %ml_gsubfile() + +%mend mp_gsubfile; diff --git a/lua/gsubfile.lua b/lua/gsubfile.lua new file mode 100644 index 0000000..004ac70 --- /dev/null +++ b/lua/gsubfile.lua @@ -0,0 +1,25 @@ +local fpath, outpath, file, fcontent + +-- configure in / out paths +fpath = sas.symget("file") +outpath = sas.symget("outfile") +if ( outpath == 0 ) +then + outpath=fpath +end + +-- open file and perform the substitution +file = io.open(fpath,"r") +fcontent = file:read() +file:close() +fcontent = string.gsub( + fcontent, + sas.symget(sas.symget("patternvar")), + sas.symget(sas.symget("replacevar")) +) + +-- write the file back out +file = io.open(outpath, "w+") +io.output(file) +io.write(fcontent) +io.close(file) \ No newline at end of file diff --git a/lua/ml_gsubfile.sas b/lua/ml_gsubfile.sas new file mode 100644 index 0000000..a39c122 --- /dev/null +++ b/lua/ml_gsubfile.sas @@ -0,0 +1,44 @@ +/** + @file ml_gsubfile.sas + @brief Compiles the gsubfile.lua lua file + @details Writes gsubfile.lua to the work directory + and then includes it. + Usage: + + %ml_gsubfile() + +**/ + +%macro ml_gsubfile(); +data _null_; + file "%sysfunc(pathname(work))/ml_gsubfile.lua"; + put 'local fpath, outpath, file, fcontent '; + put ' '; + put '-- configure in / out paths '; + put 'fpath = sas.symget("file") '; + put 'outpath = sas.symget("outfile") '; + put 'if ( outpath == 0 ) '; + put 'then '; + put ' outpath=fpath '; + put 'end '; + put ' '; + put '-- open file and perform the substitution '; + put 'file = io.open(fpath,"r") '; + put 'fcontent = file:read() '; + put 'file:close() '; + put 'fcontent = string.gsub( '; + put ' fcontent, '; + put ' sas.symget(sas.symget("patternvar")), '; + put ' sas.symget(sas.symget("replacevar")) '; + put ') '; + put ' '; + put '-- write the file back out '; + put 'file = io.open(outpath, "w+") '; + put 'io.output(file) '; + put 'io.write(fcontent) '; + put 'io.close(file) '; +run; + +%inc "%sysfunc(pathname(work))/ml_gsubfile.lua"; + +%mend ml_gsubfile; diff --git a/tests/crossplatform/mp_gsubfile.test.sas b/tests/crossplatform/mp_gsubfile.test.sas new file mode 100644 index 0000000..34c5155 --- /dev/null +++ b/tests/crossplatform/mp_gsubfile.test.sas @@ -0,0 +1,33 @@ +/** + @file + @brief Testing mp_gsubfile.sas macro + +

SAS Macros

+ @li mp_gsubfile.sas + @li mp_assert.sas + +**/ + +/** + * test 1 - simple replace + */ +%global str1; +%let file=%sysfunc(pathname(work))/file.txt; +%let pat=replace/me; +%let str=with/this; +data _null_; + file "&file"; + put "&pat"; +run; +%mp_gsubfile(file=&file, patternvar=pat, replacevar=str) +data _null_; + infile "&file"; + input; + call symputx('str1',_infile_); +run; + +%mp_assert( + iftrue=("&str1"="&str"), + desc=Check that simple replacement was successful, + outds=work.test_results +) \ No newline at end of file