Adding a substring to each line in a string in MATLAB - matlab

Say I have a string in a variable in MATLAB like the following:
this is the first line
this is the second line
this is the third line
I would like to add a fixed string at the beginning of each line. For example:
add_substring(input_string, 'add_this. ')
would output:
add_this. this is the first line
add_this. this is the second line
add_this. this is the third line
I know I can do this by looping through the input string, but I am looking for a more compact (hopefully vectorized) way to do this, perhaps using one of MATLAB built-ins such as arrayfun accumarray.

The strcat function is what you're looking for. It does vectorized concatenation of strings.
strs = {
'this is the first line'
'this is the second line'
'this is the third line'
}
strcat({'add_this. '}, strs)
With strcat, you need to put 'add_this. ' in a cell ({}) to protect it from having its trailing whitespace stripped, which is strcat's normal behavior for char inputs.

Assuming your strings are stored in a cell array then cellfun will do what you want, e.g.
s = {'this is the first line', 'this is the second line', 'this is the third line'};
prefix = 'add_this. ';
res = cellfun(#(str) strcat(prefix, str), s, 'UniformOutput', false);

Related

strsplit excluding one, but including another

A very short question. I have a string
str = 'var(:,1),var(:,2),var(:,3)';
I need to split it with strsplit by ',' but not by ':,' so that I will end up with a cell array
cel = {'var(:,1)','var(:,2)','var(:,3)'};
I am not good with regular expression at all and I tried ,^(:,) but this fails. I thought ^ is not () is group.
How can it be done?
Use a regular expression with negative lookbehind:
cel = regexp(str, '(?<!:),', 'split');

How can I add a string to the last line in multiline EditText, Matlab?

I often use this way to add a string to the last line in multiline editText.
Example: The before editText: (handles.txtLine)
line 1
line 2
line 3
and i want to add string "line 4" to it. So i do:
msg = get(handles.txtLine,'string');
msg_i = sprintf('\nline 4');
msg = [msg msg_i];
set(handles.txtLine,'string',msg)
Result:
line 1
line 2
line 3
line 4
Are there other methods to do the same function?
The String property of a multiline edit control can be set in three ways:
a multiline character array, e.g. txt1= ['line 1'; 'line 2']. Here txt1 has size 2x6.
a single line character array containing newline characters, e.g. txt2= sprintf('line 1\nline 2'). Here txt2 has size 1x13.
a cell array of strings, e.g. txt3 = {'line 1', 'line 2'}
You would add or remove text from the string in each case in different ways, and each method has advantages and disadvantages.
1 is usually inconvenient, as all your lines have to have exactly the same length, or be padded with spaces. But if that's the case, then it's easy to add or remove lines.
2 (basically the way you're doing it now) is also usually less convenient, as while it's easy to append lines, it's less easy to remove them from the middle unless you parse the string looking for newlines. But if you only ever need to add lines, it's probably fine.
I would modify the way you're using sprintf and then concatenating:
msg = sprintf('%s\n%s', msg, 'line 4');
is a simpler and more flexible syntax.
Your general method of getting, modifying and setting the String property is fine, although if you wanted you could combine it all into one starement, such as:
set(handles.txtLine, 'String', sprintf('%s\n%s', get(handles.txtLine, 'String'), 'line4'))
3 would typically be the most convenient, as long as you're comfortable with cell arrays. Each line can be whatever you like, and it's easy to add or remove items.

print cells type in Matlab

I have a cell array like:
>>text
'Sentence1'
'Sentence2'
'Sentence3'
Whenever I use
sprintf(fid,'%s\n',text)
I get an error saying:
'Function is not defined for 'cell' inputs.'
But if I put :
sprintf(fid,'%s\n',char(text))
It works but in the file appears all the sentences mixed all together like with no sense.
Can you recommend me what to do?
Whener I put text I get:
>>text
'Title '
'Author'
'comments '
{3x1} cell
That is why I can not use text{:}.
If you issue
sprintf('%s\n', text)
you are saying "print a string with a newline. The string is this cell array". That's not correct; a cell-array is not a string.
If you issue
sprintf('%s\n', char(text))
you are saying "print a string with a newline. The string is this cell array, which I convert to character array.". The thing is, that conversion results in a single character array, and sprintf will re-use the %s\n format only for multiple inputs. Moreover, it writes that single character array by column, meaning, all characters in the first column, concatenated horizontally with all characters from the second column, concatenated with all characters from the third column, etc.
Therefore, the approprate call to sprintf is something with multiple inputs:
sprintf(fid, '%s\n', text{:})
because the cell-expansion text{:} creates a comma-separated list from all entries in the cell-array, which is exactly what sprintf/fprintf expects.
EDIT As you indicate:, you have non-char entries in text. You have to check for that. If you want to pass only the strings into fprintf, use
fprintf(fid, '%s\n', text{ cellfun('isclass', text, 'char') })
if that {3x1 cell} is again a set of strings, so you want to write all strings recursively, then just use something like this:
function textWriter
text = {...
'Title'
'Author'
'comments'
{...
'Title2'
'Author2'
'comments2'
{...
'Title3'
'Author3'
'comments3'
}
}
}
text = cell2str(text);
fprintf(fid, '%s\n', text{:});
end
function out = cell2str(c)
out = {};
for ii = c(:)'
if iscell(ii{1})
S = cell2str(ii{1});
out(end+1:end+numel(S)) = S;
else
out{end+1} = ii{1};
end
end
end

Nested textscan statements

The following two statements read the first line from an input file (fid) and parse said line into strings delimited by whitespace.
a = textscan(fid,'%s',1,'Delimiter','\n');
b = textscan(a{1}{1},'%s');
I would like to know if this action can be accomplished in a single statement, having a form similar to the following (which is syntactically invalid).
b = textscan(textscan(fid,'%s',1,'Delimiter','\n'),'%s');
Thanks.
Instead of
a = textscan(fid, '%s', 1, 'Delimiter', '\n');
you can use
a = fgetl(fid);
That will return the next line in fid as a string (the newline character at the end is stripped). You can then split that line into white-space separated chunks as follows:
b = regexp(a, '\s*', 'split');
Combined:
b = regexp(fgetl(fid), '\s*', 'split');
Note that this is not 100% equivalent to your code, since using textscan adds another cell-layer (representing different lines in the file). That's not a problem, though, simply use
b = {regexp(fgetl(fid), '\s*', 'split')};
if you need that extra cell-layer.

Matlab strcat function troubles with spaces

I'm trying to accomplish this:
strcat('red ', 'yellow ', 'white ')
I expected to see "red yellow white", however, I see "redyellowwhite" on the command output. What needs to be done to ensure the spaces are concatenated properly? Thanks in advance.
Although STRCAT ignores trailing white space, it still preserves leading white space. Try this:
strcat('red',' yellow',' white')
Alternatively, you can just use the concatenation syntax:
['red ' 'yellow ' 'white ']
From the matlab help page for strcat:
"strcat ignores trailing ASCII white space characters and omits all such characters from the output. White space characters in ASCII are space, newline, carriage return, tab, vertical tab, or form-feed characters, all of which return a true response from the MATLAB isspace function. Use the concatenation syntax [s1 s2 s3 ...] to preserve trailing spaces. strcat does not ignore inputs that are cell arrays of strings. "
In fact, you can simply use the ASCII code of space: 32. So, you can solve the problem like this:
str = strcat('red', 32, 'yellow', 32, 'white');
Then you will get str = 'red yellow white'.
You can protect trailing whitespace in strcat() or similar functions by putting it in a cell.
str = strcat({'red '}, {'yellow '}, {'white '})
str = str{1}
Not very useful in this basic example. But if you end up doing "vectorized" operations on the strings, it's handy. Regular array concatenation doesn't do the 1-to-many concatenation that strcat does.
strs = strcat( {'my '}, {'red ','yellow ','white '}, 'shirt' )
Sticking 'my ' in a cell even though it's a single string will preserve the whitespace. Note you have to use the {} form instead of calling cellstr(), which will itself strip trailing whitespace.
This is all probably because Matlab has two forms of representing lists of strings: as a cellstr array, where all whitespace is significant, and as a blank-padded 2-dimensional char array, with each row treated as a string, and trailing whitespace ignored. The cellstr form most resembles strings in Java and C; the 2-D char form can be more memory efficient if you have many strings of similar length. Matlab's string manipulation functions are polymorphic on the two representations, and sometimes exhibit differences like this. A char literal like 'foo' is a degenerate one-string case of the 2-D char form, and Matlab's functions treat it as such.
UPDATE: As of Matlab R2019b or so, Matlab also has a new string array type. Double-quoted string literals make string arrays instead of char arrays. If you switch to using string arrays, it will solve all your problems here.
or you can say:
str = sprintf('%s%s%s', 'red ', 'yellow ', 'white ')