searching matlab search path with strcmp - matlab

I have written the code below. Basically it is checking if some path is already in the matlab search path or not. If it is not found then it adds the path.
The problem is the strcmp always returns a vector of zeros despite the path actually already existing in currPath. I actually copied a path from currPath to check I was getting the correct values. Not sure why this is?
% get current path
currPath = strsplit(path, ';')';
currPath = upper(currPath);
% check if required paths exist - if not add them
pathsToCheck = ['C:\SOMEFOLDER\MADEUP'];
pathsToCheck = upper(pathsToCheck);
for n = 1 : length(pathsToCheck(:, 1))
index = strcmp(currPath, pathsToCheck(n, 1));
if sum(index) > 0
addpath(pathsToCheck{t, 1}, '-end'); % add path to the end
end
end
% save changes
savepath;

The issue is that you have defined pathsToCheck as a character array and not a cell array (which I think is what you intended the way that you are looping through it).
Rather than using a for loop, you could use ismember to check which members of a cell array of strings exist in another cell array of strings.
% Note the use of pathsep to make this work across multiple operating systems
currentPath = strsplit(path, pathsep);
pathsToCheck = {'C:\SOMEFOLDER\MADEUP'};
exists = ismember(pathsToCheck, currentPath);
% If you want to ignore case: ismember(upper(pathsToCheck), upper(currentPath))
% Add the ones that didn't exist
addpath(pathsToCheck{~exists}, '-end');

Related

Extract information from path name

I want to make a script in MATLAB that saves my output data with a certain name. All information for this name is in the path from the input data, like it is shown here:
path = 'C:\projektions100\algorithm1\method_A\data1';
projection =
algorithm =
method =
data =
The script then should extract the text in the path with the keyword (f.e. method) from the adjacent backslashes so the script is more flexible in case I made a spelling mistake with some folder names.
This is what I found to extract a text between a start and a end point but I cannot simply use the backslashes since there are a few of them in the path.
How should I proceed?
You can simply use a regexp with named tokens:
>> path = 'C:\projektions100\algorithm1\method_A\data1';
>> all=regexp(path,'[^\\]+\\proje[ck]tion(?<projection>[^\\]+)\\algorithm(?<algorithm>[^\\]+)\\method(?<method>[^\\]+)\\data(?<data>.+$)','names')
all =
struct with fields:
projection: 's100'
algorithm: '1'
method: '_A'
data: '1'
The problem is on how to find the end of your keywords. Here is a bit code, which loops through the keywords and looks for them in the path (stored in p2fldr, because the variable path returns the working path in MATLAB and you overshadow it if you define it).
p2fldr = 'C:\projektions100\algorithm1\method_A\data1';
% keywords
kyWrd = {'projection','algorithm','method','data'};
Tag = cell(size(kyWrd));
for i = 1:length(kyWrd)
% get keyword
ky = kyWrd{i};
% look for it in the path
idx = strfind(p2fldr,ky);
if ~isempty(idx)
% remaining path
idx_offset = idx+strlength(ky);
prm = p2fldr(idx_offset:end);
% look for file separator '\'
idx_tmp = strfind(prm,filesep);
% if you don't find one, it is pabably the last entry, so take the
% length
if isempty(idx_tmp)
idx_tmp = length(prm)+1;
end
% this is the index where it ends
idx2 = idx_tmp(1)-1;
% assign to tag-cell
Tag{i} = prm(1:idx2);
end
end
You can build a shortcut if you know that they are always in the last 4 entries of your path, so you can use strsplit right away and index the last returned cells
str_splt = strsplit(p2fldr,filesep);
Tag = cell(size(kyWrd));
for i = 1:length(kyWrd)
% index cells
str = str_splt{end-length(kyWrd)+i};
% get keyword
ky = kyWrd{i};
Tag{i} = str(length(ky)+1:end);
end
Note that this does not care if it matches your keywords (e.g. your path says 'projektions' but I defined the keyword to be 'projection')

get 'Documents' path in Matlab

I understand you can probably use the following code to get the job done in most cases:
mydocpath = fullfile(getenv('USERPROFILE'), 'Documents');
However, if the user has moved 'Doucments' folder to a different location, for example: E:\Documents, the above code won't work, since getenv('USERPROFILE') always returns C:\Users\MY_USER_NAME.
In C#, one can use Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), which always returns the correct path regardless where 'Documents' is. Is there anything similar in Matlab?
My current solution is rather clumsy and probably unsafe:
% search in the MATLAB path lists
% this method assumes that there is always a path containing \Documents\MATLAB registered already
searchPtn = '\Documents\MATLAB';
pathList = strsplit(path,';');
strIdx = strfind(pathList, searchPtn);
candidateIdx = strIdx{find(cellfun(#isempty,strIdx)==0, 1)}(1);
myDocPath = pathList{candidateIdx}(1 : strIdx{candidateIdx}+ numel(searchPtn));
Based on #excaza 's suggestion, I came up with a solution using dos and the cmd command found here to query the registry.
% query the registry
[~,res]=dos('reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal');
% parse result
res = strsplit(res, ' ');
myDocPath = strtrim(res{numel(res)});
Edit:
If the document folder in customer's PC has not been relocated or moved to one of the environment path such as %SYSTEMROOT%, the above method would return
%SOME_ENVIRONMENT_PATH%/Documents(Or a custom folder name)
The above path will not work in Matlab's functions such as mkdir or exist, which will take %SOME_ENVIRONMENT_PATH% as a folder name. Therefore we need to check for the existence of environment path in the return value and get the correct path:
[startidx, endidx] = regexp(myDocPath,'%[A-Z]+%');
if ~isempty(startidx)
myDocPath = fullfile(getenv(myDocPath(startidx(1)+1:endidx(1)-1)), myDocPath(endidx(1)+1:end));
end
Full code:
% query the registry
[~,res]=dos('reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal');
% parse result
res = strsplit(res, ' ');
% get path
myDocPath = strtrim(res{numel(res)});
% if it returns %AAAAA%/xxxx, meaning the Documents folder is
% in some environment path.
[startidx, endidx] = regexp(myDocPath,'%[A-Z]+%');
if ~isempty(startidx)
myDocPath = fullfile(getenv(myDocPath(startidx(1)+1:endidx(1)-1)), myDocPath(endidx(1)+1:end));
end

MATLAB dir without '.' and '..'

the function dir returns an array like
.
..
Folder1
Folder2
and every time I have to get rid of the first 2 items, with methods like :
for i=1:numel(folders)
foldername = folders(i).name;
if foldername(1) == '.' % do nothing
continue;
end
do_something(foldername)
end
and with nested loops it can result in a lot of repeated code.
So can I avoid these "folders" by an easier way?
Thanks for any help!
Edit:
Lately I have been dealing with this issue more simply, like this :
for i=3:numel(folders)
do_something(folders(i).name)
end
simply disregarding the first two items.
BUT, pay attention to #Jubobs' answer. Be careful for folder names that start with a nasty character that have a smaller ASCII value than .. Then the second method will fail. Also, if it starts with a ., then the first method will fail :)
So either make sure you have nice folder names and use one of my simple solutions, or use #Jubobs' solution to make sure.
A loop-less solution:
d=dir;
d=d(~ismember({d.name},{'.','..'}));
TL; DR
Scroll to the bottom of my answer for a function that lists directory contents except . and ...
Detailed answer
The . and .. entries correspond to the current folder and the parent folder, respectively. In *nix shells, you can use commands like ls -lA to list everything but . and ... Sadly, MATLAB's dir doesn't offer this functionality.
However, all is not lost. The elements of the output struct array returned by the dir function are actually ordered in lexicographical order based on the name field. This means that, if your current MATLAB folder contains files/folders that start by any character of ASCII code point smaller than that of the full stop (46, in decimal), then . and .. willl not correspond to the first two elements of that struct array.
Here is an illustrative example: if your current MATLAB folder has the following structure (!hello and 'world being either files or folders),
.
├── !hello
└── 'world
then you get this
>> f = dir;
>> for k = 1 : length(f), disp(f(k).name), end
!hello
'world
.
..
Why are . and .. not the first two entries, here? Because both the exclamation point and the single quote have smaller code points (33 and 39, in decimal, resp.) than that of the full stop (46, in decimal).
I refer you to this ASCII table for an exhaustive list of the visible characters that have an ASCII code point smaller than that of the full stop; note that not all of them are necessarily legal filename characters, though.
A custom dir function that does not list . and ..
Right after invoking dir, you can always get rid of the two offending entries from the struct array before manipulating it. Moreover, for convenience, if you want to save yourself some mental overhead, you can always write a custom dir function that does what you want:
function listing = dir2(varargin)
if nargin == 0
name = '.';
elseif nargin == 1
name = varargin{1};
else
error('Too many input arguments.')
end
listing = dir(name);
inds = [];
n = 0;
k = 1;
while n < 2 && k <= length(listing)
if any(strcmp(listing(k).name, {'.', '..'}))
inds(end + 1) = k;
n = n + 1;
end
k = k + 1;
end
listing(inds) = [];
Test
Assuming the same directory structure as before, you get the following:
>> f = dir2;
>> for k = 1 : length(f), disp(f(k).name), end
!hello
'world
a similar solution from the one suggested by Tal is:
listing = dir(directoryname);
listing(1:2)=[]; % here you erase these . and .. items from listing
It has the advantage to use a very common trick in Matlab, but assumes that you know that the first two items of listing are . and .. (which you do in this case). Whereas the solution provided by Tal (which I did not try though) seems to find the . and .. items even if they are not placed at the first two positions within listing.
Hope that helps ;)
If you're just using dir to get a list of files and and directories, you can use Matlab's ls function instead. On UNIX systems, this just returns the output of the shell's ls command, which may be faster than calling dir. The . and .. directories won't be displayed (unless your shell is set up to do so). Also, note that the behavior of this function is different between UNIX and Windows systems.
If you still want to use dir, and you test each file name explicitly, as in your example, it's a good idea to use strcmp (or one of its relations) instead of == to compare strings. The following would skip all hidden files and folder on UNIX systems:
listing = dir;
for i = 1:length(listing)
if ~strcmp(listing(i).name(1),'.')
% Do something
...
end
end
You may also wanna exclude any other files besides removing dots
d = dir('/path/to/parent/folder')
d(1:2)=[]; % removing dots
d = d([d.isdir]) % [d.isdir] returns a logical array of 1s representing folders and 0s for other entries
I used: a = dir(folderPath);
Then used two short code that return struct:
my_isdir = a([a.isdir]) Get a struct which only has folder info
my_notdir = a(~[a.isdir]) Get a struct which only has non-folder info
Combining #jubobs and #Tal solutions:
function d = dir2(folderPath)
% DIR2 lists the files in folderPath ignoring the '.' and '..' paths.
if nargin<1; folderPath = '.'; elseif nargin == 1
d = dir(folderPath);
d = d(~ismember({d.name},{'.','..'}));
end
None of the above puts together the elements as I see the question having being asked - obtain a list only of directories, while excluding the parents.
Just combining the elements, I would go with:
function d = dirsonly(folderPath)
% dirsonly lists the unhidden directories in folderPath ignoring '.' and '..'
% creating a simple cell array without the rest of the dir struct information
if nargin<1; folderPath = '.'; elseif nargin == 1
d = dir(folderPath);
d = {d([d.isdir] & [~ismember({d.name},{'.','..'})]).name}.';
end
if hidden folders in general aren't wanted the ismember line could be replaced with:
d = {d([d.isdir] & [~strncmp({d.name},'.',1)]).name}.';
if there were very very large numbers of interfering non-directory files it might be more efficient to separate the steps:
d = d([d.isdir]);
d = {d([~strncmp({d.name},'.',1)]).name}.';
We can use the function startsWith
folders = dir("folderPath");
folders = string({folders.name});
folders = folders(~startsWith(folders,"."))
Potential Solution - just remove the fields
Files = dir;
FilesNew = Files(3:end);
You can just remove them as they are the first two "files" in the structure
Or if you are actually looking for specific file types:
Files = dir('*.mat');

dir(myFiles{m}) does't work MATLAB

myFiles = 1x7 cell
when I try
for m =1:numel(myFiles )
fil{m} = dir(myFiles {m});
fil{m}.bytes ;
end
This is not working
I got the error :
function is not defined for 'cell' inputs.
First of all you should mention the error message you get.
Now, besides that are some obvious problems:
myFiles {ii}
This is not valid syntax to index into a cell array. Perhaps removing the space helps.
Furthermore you loop over m and then use ii as an index.
Lastly you assign to fil everytime. In practice this means only the last result is stored. Perhaps assigning to fil(m) would suit your needs better.
The command dir will show you the content of a folder. As your variable is named "myFiles" I assume it contains filenames and not foldernames. So I think you're rather looking for a loop like this:
for ii = 1:numel(myFiles)
fil{ii} = which( myFiles{ii} )
end
which gives you an array with the full paths to your files. Or are you looking for the folders containing the files in "myFiles"? Then you can use:
for ii = 1:numel(myFiles)
fil{ii} = fileparts( which( myFiles{ii} ) )
end
returning you the corresponding folders.
regarding your comments:
the existence of the files/folders in "myFiles" is the only purpose?
Then you could do that:
for ii = 1:numel(myFiles)
fil(ii) = exist( which(myFiles{ii}), 'file' );
end
existMyFiles = logical(fil);
returning a logical array specifying the existence of your files.

Outputting data from for loop to .mat file using numbers in title MATLAB

I need to output .mat files for the below data. I need one file to have cell (1,1) to be Mean_RPM_list1, cell (2,1) to be Mean_RPM_list2 etc. And then I need another file to have cell(1,1) to be Mean_Torque_list1 to have cell(1,1).....and so on.
Can anybody shed any light on this for me?
Also if someone knows how to automate me calling the matrices A and B so I could have A = [Mean_rpm1:Mean_rpmMAX], that would also be very helpful.
TIA for any help.
A = [Mean_rpm1 Mean_rpm2 Mean_rpm3 Mean_rpm4 Mean_rpm5 Mean_rpm6 Mean_rpm7 Mean_rpm8 Mean_rpm9 Mean_rpm10 Mean_rpm11 Mean_rpm12];
B = [Mean_torque1 Mean_torque2 Mean_torque3 Mean_torque4 Mean_torque5 Mean_torque6 Mean_torque7 Mean_torque8 Mean_torque9 Mean_torque10 Mean_torque11 Mean_torque12];
plot(A,B,'*')
for i = 1:num_bins;
bin = first + ((i-1)/10);
eval(sprintf('Mean_RPM_list%0.f = A;',bin*10));
eval(sprintf('Mean_Torque_list%0.f = B;',bin*10));
end
First of all this is really bad idea to create a set of variables with names different by numbers. As you can see it's very difficult to deal with such variables, you always have to use eval (or other related) statements.
It's much easier to create a cell array Mean_rpm and access its elements as Mean_rpm{1}, etc.
If the vectors are numeric and have the same size you can also make a 2D/3D array. Then access as Mean_rpm(:,:,1) etc.
Next, to store a cell array to a mat-file you have to create this array in MATLAB. No options (at least for now) to do it by parts in a loop. (But you can do it for numeric vectors and matrices using matfile object.) So why do you need this intermediate Mean_RPM_list variable? Just do Mean_RPM_list{bin*10} = A in your loop.
For your first question, if you already have those variables you have to use eval in a loop. Something like
A = [];
for k=1:K
eval(sprintf('A{k} = [A, Mean_rpm%d];',k));
end
You can also get names for all similar variables and combine them.
varlist = who('Mean_rpm*');
A = cell(1,numel(varlist);
for k = 1:numel(varlist)
eval('A{k} = varlist{k};');
end
Here is one without loop using CELL2FUN:
A=cellfun(#(x)evalin('base',x),varlist,'UniformOutput',0);
You should avoid having all these individual variables around in the first place. Data types like arrays, cell arrays and structure arrays exist to help you with this. If you want each variable to be associated with a name, you can use a structure array. I've made an example below. Instead of assigning a value to Mean_rpm1 like you are doing now, assign it to meanStruct.Mean_rpm1 then save the entire structure.
% as you generate values for each variable, assign them to the
% appropriate field.
meanStruct.Mean_rpm1 = [10:10];
meanStruct.Mean_rpm2 = [12:15];
meanStruct.Mean_rpm3 = [13:20];
meanStruct.Mean_rpm4 = [14];
meanStruct.Mean_rpm5 = [15:18];
meanStruct.Mean_rpm6 = [16:20];
meanStruct.Mean_rpm7 = [17:22];
meanStruct.Mean_rpm8 = [18:22];
meanStruct.Mean_rpm9 = [19:22];
meanStruct.Mean_rpm10 = [20:22];
meanStruct.Mean_rpm11 = [21:22];
meanStruct.Mean_rpm12 = [22:23];
% save the structure array
save('meanValues.mat','meanStruct')
% load and access the structure array
clear all
load('meanValues.mat')
temp = meanStruct.Mean_rpm3