关于#matlab#的问题:用matlab写代码时不小心把系统自带的.m文件代码改了

用matlab写代码时不小心把系统自带的.m文件代码改了,不知道原来的代码了

求热心人复制个str2symInternal.m文件的代码,万分感谢!


function [mupstr, variables] = str2symInternal(S, options)
%str2symInternal Evaluate string representing symbolic expression.
%   str2symInternal(S) evaluates S as a symbolic expression, where S can be
%   a string, character vector, or cell array of character vectors.
%
%   str2symInternal(S) behavior:
%     Only executes functions on path when converting the string.
%     Does not consider variables and values from workspace.
%     Does not add variables in the input to the workspace.
%     Does not support programming statements like IF.
%     Treats assignments ('=') as equations ('==').
%
%   For numeric strings, use SYM for exact symbolic numbers and
%   VPA for floating-point numbers.
%
%   See also SUBS, SYM, SYMFUN, SYMS, SYMVAR, VPA.
%
%   Examples:
%
%      >> str2symInternal("b^2 + pi/2 + sin(x) = x^3 - 2")
%      ans =
%      b^2 + pi/2 + sin(x) == x^3 - 2
%
%      >> str2symInternal('int(x^3,x)')
%      ans =
%      x^4/4
%
%      >> str2symInternal('y(0) = 42')
%      ans =
%      y(0) == 42
%
%      >> str2symInternal({'42', 'a', 'y(0)'})
%      ans =
%      [ 42, a, y(0)]
%
%      >> str2symInternal('[42, a, y(0)]')
%      ans =
%      [ 42, a, y(0)]

%   Copyright 2017-2019 The MathWorks, Inc.

arguments
    S string
    options.Inert logical = false
end
inertMode = options.Inert;


% Convert newlines and tabs to spaces (newline are not supported by evalin)
if any(contains(S(:),newline))
    warning(message("symbolic:str2sym:NewlinesIgnored"));
end
S = regexprep(S, "\s", " ");

% Treat assigmnments as equations by replacing "=" by "==".
% --- But do not replace "=" in "<=", ">=", "~=", and "==".
S = regexprep(S, "(?<![<>~=])=(?![<>~=])", "=="); 

% Keep size of input for output
mupstr = string(zeros(size(S)));

variables = string([]);

% Iterate linearly over string array and convert to SYM.
for idx = 1:numel(S)
    % Behave like sym function on missing.
    if ismissing(S(idx))
        mupstr(idx) = "sym(NaN)";
        continue;
    end

    % Empty string results in empty sym.
    if replace(S(idx)," ","") == ""
        mupstr(idx) = "sym([])";
        continue;
    end

    if ~isempty(regexp(S(idx), "^\s*%{\s*$", "once")) || ~isempty(regexp(S(idx), "^\s*%}\s*$", "once"))
        % Note that newlines were replaced by blanks before. The 
        % only valid occurance of "%{" and "%}" to start and end 
        % a block comment is in a new line with nothing else but
        % spaces. Otherwise it is handled as single-line comment.
        error(message("symbolic:str2sym:CommentsNotSupported"));
    end
    
    % Parse string and identify objects that must be treated as SYMs.
    mt = mtree(S(idx), "-com");

    % Handle syntax errors in input
    if ~isnull(mtfind(mt, "Kind", "ERR"))
        error(message("symbolic:str2sym:UnableToConvert", string(mt)));
    end

    % Handle left curly bracket node in input
    if ~isnull(mtfind(mt, "Kind", "LC")) 
        error(message("symbolic:str2sym:CellArrayNotSupported"));
    end

    % Collect objects that need special treatment
    objects = [];

    % Comments
    comments = mtfind(mt, "Kind", "COMMENT");
    if ~isnull(comments)
        comments = struct( ...
            'type',    "comment", ...
            'name',    "", ...
            'start',   num2cell(position(comments))', ...
            'end',     num2cell(endposition(comments))', ...
            'infixstart', 0, ...
            'infixend', 0, ...
            'fnoargs', false, ...
            'dcall',   false, ...
            'isi',     false ...
        );
        objects = [objects comments]; %#ok<AGROW>
    end

    % Numbers
    numbers = mtfind(mt, "Kind", {'INT', 'DOUBLE', 'HEX', 'BINARY'});
    if ~isnull(numbers)
        numbers = struct( ...
            'type',    "number", ...
            'name',    "", ...
            'start',   num2cell(position(numbers))', ...
            'end',     num2cell(endposition(numbers))', ...
            'infixstart', 0, ...
            'infixend', 0, ...
            'fnoargs', false, ...
            'dcall',   false, ...
            'isi',     false ...
        );
        objects = [objects numbers]; %#ok<AGROW>
    end

    % Functions calls, variables and special values
    calls = mtfind(mt, "Kind", {'CALL', 'DCALL'});
    if ~isnull(calls)
        funvars = struct( ...
            'type',    "function", ...
            'name',    strings(calls.Left), ...
            'start',   num2cell(position(calls.Left))', ...
            'end',     num2cell(endposition(calls.Left))', ...
            'infixstart', 0, ...
            'infixend', 0, ...
            'fnoargs', false, ...
            'dcall',   false, ...
            'isi',     false ...
        );

        % Depending on type of call, name might need special treatment.
        wrapName = true(1,count(calls));
        cidx = indices(calls);
        for i = 1:count(calls)
            % Note that DCALL nodes always have arguments.
            % The arguments for a DCALL call are always STRINGs. 
            funvars(i).dcall = iskind(select(calls,cidx(i)), "DCALL"); 
            if ~funvars(i).dcall
                funvars(i).fnoargs = ~isempty(regexp(S(idx),"^.{" + funvars(i).end + "}\s*\(\s*\)", "once"));
                if isnull(Right(select(calls,cidx(i)))) && ~funvars(i).fnoargs
                    % Call has no arguments (= right branch of tree)  and
                    % found no name() so it's a variable or special value
                    name = funvars(i).name;
                    if name == "i" || name == "j"
                        funvars(i).type = "special";
                        funvars(i).isi = true;
                    elseif any(name == ["pi", "catalan", "eulergamma", "inf", "Inf", "nan", "NaN", "missing", "symtrue", "symfalse"])
                        funvars(i).type = "special";
                        funvars(i).isi = false;
                    elseif any(name == ["true", "false"])
                        funvars(i).type = "logical";
                        funvars(i).isi = false;
                    else
                        funvars(i).type = "variable";
                    end
                    continue;
                end
            end
            % We know: It's a function call with at least one argument.
            % Respect functions on search path: do not add sym wrapper.
            if inertMode
                wh = string([]);
            else
                wh = string(evalin("caller", "which('" + funvars(i).name + "')"));
            end
            if ~isempty(wh) && ~strcmp(wh, "variable")
                % Note: 'which' is *not* case-sensitive so we need to double-check!
                % e.g.: S:\Bsymbolic\matlab\toolbox\symbolic\symbolic\@sym\sym.m    % sym method
                wh = regexprep(wh, "\s*%.*$", ""); % for robustness
                % e.g.: built-in (S:\Bsymbolic\matlab\toolbox\matlab\datatypes\double)
                wh = regexprep(wh, "\)$", "");
                % e.g.: S:\Bsymbolic\matlab\toolbox\symbolic\symbolic\str2sym.m
                wh = regexprep(wh, "\.m$", "");
                % e.g.: plus is a built-in method           % string method
                if startsWith(wh, funvars(i).name) || endsWith(wh, funvars(i).name)
                    wrapName(i) = false;
                end
            end
        end
        objects = [objects funvars(wrapName)]; %#ok<AGROW>
    end
    
    if inertMode 
        infixNames = struct(...
            'PLUS', "_plus", ...
            'MINUS', "_subtract", ...
            'MUL',  "_mult", ...
            'DIV',  "_divide", ...
            'EXP',  "_power", ...
            'EQ', "_equal");
        infixOperators = mtfind(mt, "Kind", fieldnames(infixNames));
        if ~isnull(infixOperators)
            infixStruct = struct( ...
            'type',    "infix", ...
            'name',    num2cell(string(infixOperators.kinds))', ...
            'start',   num2cell(lefttreepos(infixOperators))', ...
            'end',     num2cell(righttreepos(infixOperators))', ...
            'infixstart', num2cell(position(infixOperators))', ...
            'infixend', num2cell(endposition(infixOperators))', ...
            'fnoargs', false, ...
            'dcall',   false, ...
            'isi',     false ...
            );
            objects = [objects infixStruct]; %#ok<AGROW>
        end
    end
    
    % Manipulate given string: take action on each identified object.
    T = S(idx);
    for i = 1:numel(objects)
        switch objects(i).type
            case "comment"
                % Remove comment
                [T, objects] = removeStringBetween(T, objects(i).start, objects(i).end, objects);
            case "number"
                % Rewrite <o> to sym("<o>")
                [T, objects] = addStringAtStart(T, objects, i, "sym(""");
                [T, objects] = addStringAtEnd (T, objects, i,  """)");
            case "variable"
                if nargout >= 2
                   variables = union(variables, getString(T, objects(i))); 
                end
                [T, objects] = addStringAtStart(T, objects, i, "sym(""");
                [T, objects] = addStringAtEnd (T, objects, i,  """)");
            case "logical" 
                if inertMode 
                  [T, objects] = addStringAtStart(T, objects, i, "sym(");
                  [T, objects] = addStringAtEnd(T, objects, i,   ")");
                end  
            case "special"
                % Rewrite <o> to sym(<o>)
                if objects(i).isi
                    [T, objects] = addStringAtStart(T, objects, i, "1");
                end
                [T, objects] = addStringAtStart(T, objects, i, "sym(");
                [T, objects] = addStringAtEnd(T, objects, i,   ")");
            case "function"
                % Rewrite 'f(<any>)' to 'feval_internal(symengine, sym("f"), <any>)'
                if objects(i).dcall
                    continue;
                end
                pos = objects(i).end;
                while(extractBetween(T,pos,pos) ~= "(")
                    pos = pos + 1;
                end
                T = replaceBetween(T, pos, pos, ",");
                if inertMode 
                   [T, objects] = insertStringBefore(T, pos, ")""", objects);
                end  
                if objects(i).fnoargs
                    % Rewrite 'f()' to 'feval_internal(symengine, sym("f"), "null()")'
                    [T, objects] = insertStringAfter(T, pos,   """null()""",                     objects);
                end
                if inertMode
                    [T, objects] = insertStringBefore(T, pos, """""", objects);
                    [T, objects] = addStringAtStart(T, objects, i, "feval_internal(symengine, ""symobj::inertproc(""""");
                else
                    [T, objects] = addStringAtStart(T, objects, i, "feval_internal(symengine,sym(""");
                    [T, objects] = addStringAtEnd (T, objects, i,  """)");
                end
            case "infix"
                % can only happen in inert mode
                % replace operator by comma
                pos = objects(i).infixstart;
                endpos = objects(i).infixend;
                % replace the the operator by a comma, e.g., "2 * 2" -> "2 , 2" 
                [T, objects] = replaceStringBetween(T, objects, pos, endpos, ",");
                % declare the object non-infix
                objects(i).infixstart = 0;
                objects(i).infixend = 0;
                % Convert the MATLAB name to a MuPAD name, 
                % e.g., "MUL" -> "_mult"
                mupname = infixNames.(objects(i).name);
                % add MuPAD name in front
                [T, objects] = addStringAtStart(T, objects, i, "feval_internal(symengine, ""hold(" + mupname + ")"",");
                % close the bracket "feval_internal(..."
                [T, objects] = addStringAtEnd(T, objects, i,   ")");
        end
    end

    if replace(T," ","") == ""
        mupstr(idx) = "sym([])";
    else
        mupstr(idx) = T;
    end
end

end


% Helper: getString
% returns the substring of text that corresponds to obj
function T = getString(text, obj)
range = obj.start : obj.end;
T = text{1}(range);
end

% Helper: removeStringBetween
function [text, objs] = removeStringBetween(text, left, right, objs)
text = replaceBetween(text, left, right, "");
objs = adaptStringPositions(objs, left, left-right-1);
end

% Helper: replaceStringBetween
% Replace the string between left and right by newtext
function [text, objs] = replaceStringBetween(text, objs, left, right, newtext)
text = replaceBetween(text, left, right, newtext);
len = strlength(newtext);
objs = adaptStartPositions(objs, left+1, left-right-1+len);
objs = adaptEndPositions(objs, left, left-right-1+len);
objs = adaptInfixPositions(objs, left, left-right-1+len);
end

% Helper: insertStringBefore
function [text, objs] = insertStringBefore(text, pos, textBefore, objs)
text = insertBefore(text, pos, textBefore);
objs = adaptStringPositions(objs, pos, strlength(textBefore));
end

% Helper addStringAtStart
% adds a string at the start of the n-th object
function [text, objs] = addStringAtStart(text, objs, n, textBefore)
len = strlength(textBefore);
startpos = objs(n).start;
text = insertBefore(text, startpos, textBefore);
for i = 1:numel(objs)
    if objs(i).start == startpos && objs(i).end < objs(n).end ...
            || objs(i).start > startpos
        % If objs(i) is an inner object (subtree) of objs(n),
        % or if it is a later object, modify the start.
        % Example: 2*2 + 3 -> _plus(2*2, 3). The start of 2*2 is shifted.
        objs(i).start = objs(i).start + len;
        % else objs(n) is a subtree of objs(i), or an object to the left.
        % Do not modify the start.
        % Example: 2*2 + 3 -> _mult(2, 2) + 3. The sum still begins at 1.
    end
end
% adapt infix and end positions of all objects, including objs(n)
objs = adaptInfixPositions(objs, startpos, len);
objs = adaptEndPositions(objs, startpos, len);
end


% Helper addStringAtEnd
% adds a string at the end of the n-th object
function [text, objs] = addStringAtEnd(text, objs, n, textAfter)
len = strlength(textAfter);
endpos = objs(n).end;
text = insertAfter(text, endpos, textAfter);
for i = 1:numel(objs)
    if objs(i).end == endpos && objs(i).start <= objs(n).start ...
            || objs(i).end > endpos
        % If objs(n) is a subtree of objs(i), or i=n,
        % or if objs(i) is a later object, modify the end of objs(i).
        % Example: _plus(3 + 2*2 -> _plus(3, 2*2).
        % The sum includes the closing bracket, the end of the product
        % remains the same.
        objs(i).end = objs(i).end + len;
    end
end
% adapt infix and start positions of all objects on the right
% of objs(n).
objs = adaptInfixPositions(objs, endpos, len);
objs = adaptStartPositions(objs, endpos, len);
end


% Helper: insertStringAfter
function [text, objs] = insertStringAfter(text, pos, textAfter, objs)
text = insertAfter(text, pos, textAfter);
objs = adaptStringPositions(objs, pos, strlength(textAfter));
end

function objs = adaptInfixPositions(objs, pos, len)
for i=1:numel(objs)
    if pos <= objs(i).infixstart
        objs(i).infixstart = objs(i).infixstart + len;
    end
    if pos <= objs(i).infixend
        objs(i).infixend = objs(i).infixend + len;
    end
end
end

function objs = adaptStartPositions(objs, pos, len)
for i=1:numel(objs)
    if pos <= objs(i).start
        objs(i).start = objs(i).start + len;
    end
end
end


function objs = adaptEndPositions(objs, pos, len)
for i=1:numel(objs)
    if pos <= objs(i).end
        objs(i).end = objs(i).end + len;
    end
end
end

% Helper: adaptStringPositions
function objs = adaptStringPositions(objs, pos, len)
for i=1:numel(objs)
    if pos <= objs(i).start
        objs(i).start = objs(i).start + len;
    end
    if pos <= objs(i).end
        objs(i).end = objs(i).end + len;
    end
end
objs = adaptInfixPositions(objs, pos, len);
end