1######################################################################## 2## 3## Copyright (C) 2008-2021 The Octave Project Developers 4## 5## See the file COPYRIGHT.md in the top-level directory of this 6## distribution or <https://octave.org/copyright/>. 7## 8## This file is part of Octave. 9## 10## Octave is free software: you can redistribute it and/or modify it 11## under the terms of the GNU General Public License as published by 12## the Free Software Foundation, either version 3 of the License, or 13## (at your option) any later version. 14## 15## Octave is distributed in the hope that it will be useful, but 16## WITHOUT ANY WARRANTY; without even the implied warranty of 17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18## GNU General Public License for more details. 19## 20## You should have received a copy of the GNU General Public License 21## along with Octave; see the file COPYING. If not, see 22## <https://www.gnu.org/licenses/>. 23## 24######################################################################## 25 26## -*- texinfo -*- 27## @deftypefn {} {@var{varname} =} genvarname (@var{str}) 28## @deftypefnx {} {@var{varname} =} genvarname (@var{str}, @var{exclusions}) 29## 30## This function is obsolete. Use @code{matlab.lang.makeValidName} or 31## @code{matlab.lang.makeUniqueStrings} instead. 32## 33## Create valid unique variable name(s) from @var{str}. 34## 35## If @var{str} is a cellstr, then a unique variable is created for each cell 36## in @var{str}. 37## 38## @example 39## @group 40## genvarname (@{"foo", "foo"@}) 41## @result{} 42## @{ 43## [1,1] = foo 44## [1,2] = foo1 45## @} 46## @end group 47## @end example 48## 49## If @var{exclusions} is given, then the variable(s) will be unique to each 50## other and to @var{exclusions} (@var{exclusions} may be either a string or a 51## cellstr). 52## 53## @example 54## @group 55## x = 3.141; 56## genvarname ("x", who ()) 57## @result{} x1 58## @end group 59## @end example 60## 61## Note that the result is a char array or cell array of strings, not the 62## variables themselves. To define a variable, @code{eval()} can be used. 63## The following trivial example sets @code{x} to 42. 64## 65## @example 66## @group 67## name = genvarname ("x"); 68## eval ([name " = 42"]); 69## @result{} x = 42 70## @end group 71## @end example 72## 73## This can be useful for creating unique struct field names. 74## 75## @example 76## @group 77## x = struct (); 78## for i = 1:3 79## x.(genvarname ("a", fieldnames (x))) = i; 80## endfor 81## @result{} x = 82## @{ 83## a = 1 84## a1 = 2 85## a2 = 3 86## @} 87## @end group 88## @end example 89## 90## Since variable names may only contain letters, digits, and underscores, 91## @code{genvarname} will replace any sequence of disallowed characters with 92## an underscore. Also, variables may not begin with a digit; in this case 93## an @samp{x} is added before the variable name. 94## 95## Variable names beginning and ending with two underscores @qcode{"__"} are 96## valid, but they are used internally by Octave and should generally be 97## avoided; therefore, @code{genvarname} will not generate such names. 98## 99## @code{genvarname} will also ensure that returned names do not clash with 100## keywords such as @qcode{"for"} and @qcode{"if"}. A number will be 101## appended if necessary. Note, however, that this does @strong{not} include 102## function names such as @qcode{"sin"}. Such names should be included in 103## @var{exclusions} if necessary. 104## @seealso{matlab.lang.makeValidName, matlab.lang.makeUniqueStrings, 105## namelengthmax, isvarname, iskeyword, exist, who, tempname, eval} 106## @end deftypefn 107 108function varname = genvarname (str, exclusions = {}) 109 110 persistent warned = false; 111 if (! warned) 112 warned = true; 113 warning ("Octave:legacy-function", 114 "genvarname is obsolete; use matlab.lang.makeValidName or matlab.lang.makeUniqueStrings instead\n"); 115 endif 116 117 if (nargin < 1 || nargin > 2) 118 print_usage (); 119 endif 120 121 strinput = ischar (str); 122 ## Process the inputs 123 if (strinput) 124 if (rows (str) != 1) 125 error ("genvarname: if more than one STR is given, it must be a cellstr"); 126 endif 127 str = {str}; 128 elseif (! iscellstr (str)) 129 error ("genvarname: STR must be a string or cellstr"); 130 endif 131 132 if (ischar (exclusions)) 133 if (rows (exclusions) != 1) 134 error ("genvarname: if more than one exclusion is given, it must be a cellstr"); 135 endif 136 exclusions = {exclusions}; 137 elseif (! iscellstr (exclusions)) 138 error ("genvarname: EXCLUSIONS must be a string or cellstr"); 139 else 140 exclusions = exclusions(:); 141 endif 142 143 varname = cell (size (str)); 144 for i = 1:numel (str) 145 ## Perform any modifications to the varname to make sure that it is 146 ## a valid variable name. 147 148 ## remove invalid characters 149 str{i}(! (isalnum (str{i}) | str{i} == "_")) = "_"; 150 ## do not use keywords 151 if (iskeyword (str{i})) 152 firstcharacter = toupper (str{i}(1)); 153 str{i} = ["x", firstcharacter, str{i}(2:end)]; 154 endif 155 ## The variable cannot be empty 156 if (isempty (str{i})) 157 str{i} = "x"; 158 endif 159 ## Leading underscores are not Matlab compatible 160 if (str{i}(1) == "_") 161 str{i} = ["x", str{i}]; 162 endif 163 ## it cannot start with a number 164 if (isdigit (str{i}(1))) 165 str{i} = ["x", str{i}]; 166 endif 167 168 ## make sure that the variable is unique relative to other variables 169 ## and the exclusions list 170 excluded = any (strcmp (str{i}, exclusions)); 171 if (excluded && isdigit (str{i}(end))) 172 ## if it is not unique and ends with a digit, add an underscore to 173 ## make the variable name more readable ("x1_1" instead of "x11") 174 str{i} = [str{i}, "_"]; 175 endif 176 varname(i) = str(i); 177 idx = 0; 178 while (excluded) 179 idx += 1; 180 varname{i} = sprintf ("%s%d", str{i}, idx); 181 excluded = any (strcmp (varname{i}, exclusions)); 182 endwhile 183 exclusions(end+1) = varname(i); 184 endfor 185 186 if (strinput) 187 varname = varname{1}; 188 endif 189 190endfunction 191 192 193## a single argument 194%!assert (genvarname ("a"), "a") 195## a single argument with a non-conflicting exception 196%!assert (genvarname ("a", "b"), "a") 197## a single argument with a conflicting exception 198%!assert (genvarname ("a", "a"), "a1") 199## a single argument as a cell 200%!assert (genvarname ({"a"}), {"a"}) 201%!assert (genvarname ({"a"}, "b"), {"a"}) 202%!assert (genvarname ({"a"}, {"b"}), {"a"}) 203%!assert (genvarname ({"a"}, "a"), {"a1"}) 204%!assert (genvarname ({"a"}, {"a"}), {"a1"}) 205## Test different arguments 206## orientation 207%!assert (genvarname ({"a" "b"}), {"a" "b"}) 208%!assert (genvarname ({"a";"b"}), {"a";"b"}) 209%!assert (genvarname ({"a" "a"}), {"a" "a1"}) 210%!assert (genvarname ({"a" "b";"c" "d"}), {"a" "b";"c" "d"}) 211%!assert (genvarname ({"a" "a" "a";"a" "a" "a"}), {"a" "a2" "a4";"a1" "a3" "a5"}) 212## more than one repetition 213%!assert (genvarname ({"a" "a" "a"}), {"a" "a1" "a2"}) 214%!assert (genvarname ({"a" "a" "a"}, {"a" "a1" "a2"}), {"a3" "a4" "a5"}) 215## more than one repetition not in order 216%!assert (genvarname ({"a" "b" "a" "b" "a"}), {"a" "b" "a1" "b1" "a2"}) 217## Variable name munging 218%!assert (genvarname ("__x__"), "x__x__") 219%!assert (genvarname ("123456789"), "x123456789") 220%!assert (genvarname ("_$1__"), "x__1__") 221%!assert (genvarname ("__foo__", "x__foo__"), "x__foo__1") 222%!assert (genvarname ("1million_and1", "x1million_and1"), "x1million_and1_1") 223%!assert (genvarname ({"", "", ""}), {"x", "x1", "x2"}) 224%!assert (genvarname ("if"), "xIf") 225%!assert (genvarname ({"if", "if", "if"}), {"xIf", "xIf1", "xIf2"}) 226## Exclusions in odd format 227%!assert (genvarname ("x", {"a", "b"; "x", "d"}), "x1") 228 229## Test input validation 230%!error genvarname () 231%!error genvarname (1,2,3) 232%!error <more than one STR is given, it must be a cellstr> genvarname (char ("a", "b", "c")) 233%!error <STR must be a string or cellstr> genvarname (1) 234%!error <more than one exclusion is given, it must be a cellstr> genvarname ("x", char ("a", "b", "c")) 235%!error <EXCLUSIONS must be a string or cellstr> genvarname ("x", 1) 236