missing genvarname, with 'patch'
Robert Platt
robert.platt at postgrad.manchester.ac.uk
Fri Mar 7 07:58:37 CST 2008
Darn it, I knew I'd do something stupid. I tested much of this code but
forgot to check the cell array input. This is correct:
## Copyright (C) 2008 Robert Platt
##
## This file is part of Octave.
##
## Octave is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or (at
## your option) any later version.
##
## Octave is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Octave; see the file COPYING. If not, see
## <http://www.gnu.org/licenses/>.
## -*- texinfo -*-
## @deftypefn {Function File} {} genvarname (@var{ideal}, @var{avoid},
@var{allowTwoUnderscores})
## Returns a valid variable name in string format based upon @var{ideal}.
## If @var{ideal} is a cell array of strings, then a cell array of valid
## names base upon each string in @var{ideal} is returned instead.
##
## Optionally, names to be avoided by genvarname can be provided in
## @var{avoid} (which can be a string or cell array). genvarname will append
## a number to the generated variable name if it clashes with any name in
## @var{avoid}. This can be used with the command who() to prevent names
## that already exist in the the workspace from being returned. For example:
##
## @example
## x = 3.141;
## genvarname('x', who())
## @result{}
## x1
## @end example
##
## Variable names beginning with two underscores '__' are valid but
## they are used internally by octave and should usually be avoided.
## genvarname therefore will not generate variable names beginning
## with two underscores. To turn off this behaviour, the optional
## argument @var{allowTwoUnderscores} can be set to true.
##
## For example, the default behaviour removes an underscore in the
## following case:
##
## @example
## genvarname('__x')
## @result{}
## _x
## @end example
##
## However, the following code does not:
##
## @example
## genvarname('__x', '', true);
## @result{}
## __x
## @end example
##
## Since variable names may only contain letters, digits and underscores,
## genvarname replaces any sequence of unallowed characters with
## an underscore. Also, variables may not begin with a digit; in this
## case an underscore is also added before the variable name.
##
## genvarname will also make sure that returned names do not clash with
## keywords such as 'for' and 'if'. A number will be appended if necessary.
## Note, however, that this does @strong{not} include function names,
such as 'sin'.
## Such names should be included in @var{avoid} if necessary.
## @end deftypefn
function varname = genvarname(ideal, avoid, allowTwoUnderscores)
if nargin == 1
% turn avoid into an empty char array
avoid = {};
% default is to prevent two underscores at beginning of varname
allowTwoUnderscores = false;
elseif nargin == 2 || nargin == 3
% turn char array into 1x1 cell array of strings
if ischar(avoid)
avoid = {avoid};
elseif ~iscellstr(avoid)
error('genvarname: avoid must be a char array or cell array of
strings');
end
if nargin == 3
if ~islogical(allowTwoUnderscores)
error('genvarname: allowTwoUnderscores must be of type
logical');
end
else
% default is to prevent two underscores at beginning of varname
allowTwoUnderscores = false;
end
else
print_usage();
end
if ischar(ideal)
varname = genvarname_onestring(ideal, avoid, allowTwoUnderscores);
elseif iscellstr(ideal)
f = @(x) genvarname_onestring(x, avoid, allowTwoUnderscores);
varname = cellfun(f, ideal, 'UniformOutput', false);
else
error('genvarname: ideal must be a char array or cell array of
strings');
end
end
function varname = genvarname_onestring(ideal, avoid, allowTwoUnderscores)
% precondition: ideal is a char array and avoid is a cell array of strings
% this is checked in the calling genvarname routhine
varname = ideal;
% replace any non-word characters with an underscore
varname = regexprep(varname, '(\W+)', '_');
% Variable names can't begin with a number, so prepend underscore
% eg '12foo' would become '_12foo'
varname = regexprep(varname, '^(\d)', '_$1', 'once');
% In Octave, two underscores are usually reserved
% We can allow them with allowTwoUnderscores == true
if ~allowTwoUnderscores
varname = regexprep(varname, '^_{2,}', '_', 'once');
end
if isempty(varname)
varname = 'x';
end
% Append next available number to name to make sure varname is not
% in avoid and not a keyword
% start with varname, and the first number that would be appended is 1
testUnique = varname;
appendNo = 1;
% just to be extra nice, we append _1, _2, ... instead of 1, 2, 3
% if the variable ends with a number. This means that 'x2' would become
% 'x2_1' rather than 'x21' if it is found in the avoid cell array.
% This improves readablity.
if isempty(regexp(varname, '\d$', 'once'))
% not ending in a digit, so no underscore.
baseVarname = varname;
else
% ends with a digit, append underscore.
% (note: we never append this extra underscore if there is already
% one at the end, so there's no danger of allowing two underscores
% at the beginning of the name)
baseVarname = strcat(varname, '_');
end
% this is the loop which appends the next available number
while any(strcmp(testUnique, avoid)) || iskeyword(testUnique)
testUnique = strcat(baseVarname, num2str(appendNo));
appendNo = appendNo + 1;
end
varname = testUnique;
end
More information about the Bug-octave
mailing list