Evaluate equation but ignore order of mathematical operations and parentheses - string

I'm trying to write a function that ignores the order of mathematical operations and parentheses. The function just evaluates operators from left to right. (for +-*/^)
Example 1: 5 - 3 * 8^2 returns 256.
Example 2: 4 / 2 - 1^2 + (5*3) returns 18.
Here's what I did:
function out = calc(num)
[curNum, num] = strtok(num, '+-*/^');
out = str2num(curNum);
while ~isempty(num)
sign = num(1);
[curNum, num] = strtok(num, '+-*/^');
switch sign
case '+'
out = out + str2num(curNum);
case'-'
out = out - str2num(curNum);
case '*'
out = out.*str2num(curNum);
case '/'
out = out./str2num(curNum);
case '^'
out = out.^str2num(curNum);
end
end
end
My function doesn't ignore the left to right rule. How do I correct for this?

Your first example fails because you are splitting the string with the +-*/ delimiters, and you omitted the ^. You should change this to +-*/^ in lines 2 and 6.
Your second example fails because you aren't telling your program how to ignore the ( and ) characters. You should strip them before you enter the switch statement.
curNum = strrep(curNum,'(','')
curNum = strrep(curNum,')','')
switch sign
...

This is a way without any switch statements.
str = '4 / 2 - 1^2 + (5*3)'
%// get rid of spaces and brackets
str(regexp(str,'[ ()]')) = []
%// get numbers
[numbers, operators] = regexp(str, '\d+', 'match','split')
%// get number of numbers
n = numel(numbers);
%// reorder string with numbers closing brackets and operators
newStr = [numbers; repmat({')'},1,n); operators(2:end)];
%// add opening brackets at the beginning
newStr = [repmat('(',1,n) newStr{:}]
%// evaluate
result = eval(newStr)
str =
4/2-1^2+5*3
newStr =
((((((4)/2)-1)^2)+5)*3)
result =
18

Related

Is there a way to replace characters in a string from index 0 to index -4 (i.e. all but last 4 characters) with a '#'

For example, If my string was 'HelloWorld'
I want the output to be ######orld
My Code:
myString = 'ThisIsAString'
hashedString = string.replace(string[:-4], '#')
print(hashedString)
Output >> #ring
I expected the output to have just one # symbol since it is replacing argument 1 with argument 2.
Can anyone help me with this?
You could multiply # by the word length - 4 and then use the string slicing.
myString = 'HelloWorld'
print('#' * (len(myString) - 4) + myString[-4:])
myString = 'ThisIsAString'
print('#' * (len(myString) - 4) + myString[-4:])
string.replace(old, new) replaces all instances of old with new. So the code you provided is actually replacing the entire beginning of the string with a single pound sign.
You will also notice that input like abcdabcd will give the output ##, since you are replacing all 'abcd' substrings.
Using replace, you could do
hashes = '#' * len(string[:-4])
hashedString = string.replace(string[:-4], hashes, 1)
Note the string multiplication to get the right number of pound symbols, and the 1 passed to replace, which tells it only to replace the first case it finds.
A better method would be to not use replace at all:
hashes = '#' * (len(string) - 4)
leftover = string[-4:]
hashedString = hashes + leftover
This time we do the same work with getting the pound sign string, but instead of replacing we just take the last 4 characters and add them after the pound signs.

Apply backspace within a string

I have a string which includes backspace. Displaying it to the commandline will 'apply' the backspaces such that each backspace and the non-backspace character which immediately precedes it cannot be seen:
>> tempStr = ['aaab', char(8)]
tempStr =
aaa
Yet the deletion operation operation only happens when displaying the string. It still has the backspace character, and the 'b', inside it:
>> length(tempStr)
ans =
5
I'm looking for a minimal (ideally some sort of string processing built in) function which applies the backspace operation:
>>f(tempStr)
ans =
'aaa'
It may also help to know that I have an enumerations class over the alphabet 'a' to 'z' plus ' ' and backspace (to store my own personal indexing of the letters, images associated with each etc.). It'd be real spiffy to have this backspace removal operation be a method of the superclass that acts on a vector of its objects.
You can do it with a simple function using a while loop:
function s = printb(s)
while true
% Find backspaces
I = strfind(s, char(8));
% Break condition
if isempty(I), break; end
% Remove elements
if I(1)==1
s = s(2:end);
else
s(I(1)-1:I(1)) = [];
end
end
and the test gives:
s = [char(8) 'hahaha' char(8) char(8) '!'];
numel(s) % returns 10
z = printb(s) % returns 'haha!'
numel(z) % returns 5
This is not really "minimal", but as far as my knowlegde goes I don't think this is feasible with regular expressions in Matlab.
Best,
Your problem can be solved very elegantly using regular expressions:
function newStr = applyBackspaces(tempStr)
newStr = tempStr;
while (sum(newStr==char(8))>0) % while there is at least one char(8) in newStr do:
tmp = newStr; % work on previous result
if (tmp(1) == char(8)) % if first character is char(8)
newStr = tmp(2:end); % then suppress first character
else % else delete all characters just before a char(8)
newStr = regexprep(tmp,[ '.' char(8)],''); % as well as char(8) itself.
end
end
end
In essence, what my function does is delete the character just before the backspace until there are no more backspaces in your input string tempStr.
To test if it works, we check the output and the length of the string:
>> tempStr = ['abc', char(8), 'def', char(8), char(8), 'ghi']
tempStr =
abdghi
>> length(tempStr)
ans =
12
>> applyBackspaces(tempStr)
ans =
abdghi
>> length(applyBackspaces(tempStr))
ans =
6
Hence, tempStr and applyBackspaces(tempStr) show the same string, but applyBackspaces(tempStr) is the same length as the number of characters displayed.

Does MATLAB have a strip function for strings?

Is there a simple function f such that
f(' hello, world! ' ) == 'hello, world!'
I can strip out the spaces (or any character for that matter) using regexes, but this seems like applying a hammer to the problem. I'd just like to know if there is something simple which I've missed.
No need to use a hammer, simply use strtrim.
From the documentation:
S = strtrim(str) returns a copy of string str with all leading and
trailing white-space characters removed. A white-space character is
one for which the isspace function returns logical 1 (true).
To remove the spaces on the side of the string, use the strtrim command.
Since Matlab version 2016b, you can use the built-in strip() function.
For those who do not have the newer matlab version, here is my self-defined function, which also does not have the limitation of exact one char when strCharacter is passed in as strip()
function result = trim(s,varargin)
% Merge multiple spaces to single space in the middle
% remove trailing/leading spaces
% trim(s [, how [,chars]])
% s: a string
% how: a num 1=left only;
% 2=right only;
% 3=left and right;
% 4 (default)=left and right and merge middle
% chars: if not given (default), space
% if given, remove consecutive character instead
%
if nargin == 1
how = 4;
chars = ' ';
elseif nargin == 2
how = varargin{1};
chars = ' ';
elseif nargin == 3
how = varargin{1};
chars = varargin{2};
end % end if nargin
if strcmp(chars,' '), chars='\s'; end
if how==1
expression = sprintf('^(%s)+',chars);
elseif how==2
expression = sprintf('(%s)+$',chars);
elseif how==3
expression = sprintf('^(%s)+|(%s)+$',chars,chars);
elseif how==4
expression = sprintf('(?<=[(%s)])(%s)*|^(%s)+|(%s)+$',chars,chars,chars,chars);
end % end if how
result = regexprep(s, expression, '');
end

string matching in matlab

I have two short (S with the size of 1x10) and very long (L with the size of 1x1000) strings and I am going to find the locations in L which are matched with S.
In this specific matching, I am just interested to match some specific strings in S (the black strings). Is there any function or method in matlab that can match some specific strings (for example string numbers of 1, 5, 9 in S)?
If I understand your question correctly, you want to find substrings in L that contain the same letters (characters) as S in certain positions (let's say given by array idx). Regular expressions are ideal here, so I suggest using regexp.
In regular expressions, a dot (.) matches any character, and curly braces ({}) optionally specify the number of desired occurrences. For example, to match a string of length 6, where the second character is 'a' and the fifth is 'b', our regular expression could be any of the following syntaxes:
.a..b.
.a.{2}b.
.{1}a.{2}b.{1}
any of these is correct. So let's construct a regular expression pattern first:
in = num2cell(diff([0; idx(:); numel(S) + 1]) - 1); %// Intervals
ch = num2cell(S(idx(:))); %// Matched characters
C = [in(:)'; ch(:)', {''}];
pat = sprintf('.{%d}%c', C{:}); %// Pattern for regexp
Now all is left is to feed regexp with L and the desired pattern:
loc = regexp(L, pat)
and voila!
Example
Let's assume that:
S = 'wbzder'
L = 'gabcdexybhdef'
idx = [2 4 5]
First we build a pattern:
in = num2cell(diff([0; idx(:); numel(S) + 1]) - 1);
ch = num2cell(S(idx(:)));
C = [in(:)'; ch(:)', {''}];
pat = sprintf('.{%d}%c', C{:});
The pattern we get is:
pat =
.{1}b.{1}d.{0}e.{1}
Obviously we can add code that beautifies this pattern into .b.de., but this is really an unnecessary optimization (regexp can handle the former just as well).
After we do:
loc = regexp(L, pat)
we get the following result:
loc =
2 8
Seems correct.

Is it possible to concatenate a string with series of number?

I have a string (eg. 'STA') and I want to make a cell array that will be a concatenation of my sting with a numbers from 1 to X.
I want the code to do something like the fore loop here below:
for i = 1:Num
a = [{a} {strcat('STA',num2str(i))}]
end
I want the end results to be in the form of {<1xNum cell>}
a = 'STA1' 'STA2' 'STA3' ...
(I want to set this to a uitable in the ColumnFormat array)
ColumnFormat = {{a},... % 1
'numeric',... % 2
'numeric'}; % 3
I'm not sure about starting with STA1, but this should get you a list that starts with STA (from which I guess you could remove the first entry).
N = 5;
[X{1:N+1}] = deal('STA');
a = genvarname(X);
a = a(2:end);
You can do it with combination of NUM2STR (converts numbers to strings), CELLSTR (converts strings to cell array), STRTRIM (removes extra spaces)and STRCAT (combines with another string) functions.
You need (:) to make sure the numeric vector is column.
x = 1:Num;
a = strcat( 'STA', strtrim( cellstr( num2str(x(:)) ) ) );
As an alternative for matrix with more dimensions I have this helper function:
function c = num2cellstr(xx, varargin)
%Converts matrix of numeric data to cell array of strings
c = cellfun(#(x) num2str(x,varargin{:}), num2cell(xx), 'UniformOutput', false);
Try this:
N = 10;
a = cell(1,N);
for i = 1:N
a(i) = {['STA',num2str(i)]};
end

Resources