1
votes

Say I have a directory full of filenames such as:

1242349_blabla.wav
fdp23424_asdf.wav
o2349_0.wav

and I have an input text file listing unique IDs on each newline coinciding with numbers within these filenames (e.g. '23424' for the second filename above).

I'd like to construct a struct of filenames only containing those filenames in that directory that coincide with some ID in the input text file:

fid = fopen('input.txt');
input = textscan(fid, '%s', 'Delimiter', '\n');

filenames = dir(fullfile('/somedir/', '*.wav'));

for i = 1:length(filenames)
    for j = 1:length(input)
        if (strfind(input{1}(j), filenames(i).name)) ~= [])
           % create new struct with chosen filenames
        end
    end
end 

However, I get the error "undefined function 'ne' for input arguments of type 'cell'". I've tried loads of options to no avail. Also, the input evaluates to a 38x1 cell, but which has length 1, so the inner loop will only go once... Any ideas?

2
You should always use the isempty function as opposed to ==[] in MATLAB. - MrAzzaman

2 Answers

1
votes

I would use regular expressions to search for occurrences of the ID in your cell array. Regular expressions are designed to search for patterns in a particular string for you. Because you want to search for specific numbers in a set of strings, I would certainly recommend you use it. Specifically, use the regexp function, and the pattern you want to search for is the ID that you want are searching for.

How regexp works is that you can provide a cell array of strings, and the output will be another cell array where each element is a numeric array that determines the starting index of where the particular pattern you're looking for starts for a particular string in the cell array. Should the array be empty, this means that we didn't find any pattern that matched what you're looking for. If it isn't empty, then it will contain the starting index of where the ID is located in the string. This doesn't really matter - you want to determine whether the ID exists in a particular string, and so checking to see whether each array is empty is what will be useful.

As such, given your filenames that you read through dir, we can create a cell array that stores just the file names themselves, run regexp, then filter out those file names that don't contain the ID you want. Something like this:

f = dir(fullfile('/somedir/', '*.wav'));
filenames = {f.name};
ID = 23424;
check = regexp(filenames, num2str(ID));
filtered_ind = cellfun(@isempty, check);
final_files = f(~filtered_ind);

The first line of code reads the files from your desired directory. The second line of code extracts the names from each name field of the structure as a cell array. The third line is the ID you want to check for. The fourth line does a regexp call on the file names and searches for those file names that contain your desired number. Note that we need to convert the number to a string, as the pattern is expected to be a string. The next line after that finds those filenames that do not have the ID you are looking for, and the last line simply finds those files that do have the ID you're looking for.

You can then go ahead and start your processing. Specifically, you can loop over this cell array and go ahead and create your structures per element in this cell:

for i = 1:length(final_files)
    s = final_files(i);  %// Get the dir structure for a file that passed the ID check

    %// Create your structure now...
    %// ...
end 

However, you have a series of IDs that you want to check. We can simply take the code above and apply a loop to it. In other words, you'd do something like:

fid = fopen('input.txt');
input = textscan(fid, '%s', 'Delimiter', '\n');
IDs = input{1};

f = dir(fullfile('/somedir/', '*.wav'));
filenames = {f.name};

for idx = 1 : length(IDs)
    %// Get an ID
    ID = IDs{idx};

    %// Do our checking and filter out those files that don't contain our ID
    check = regexp(filenames,ID);
    filtered_ind = cellfun(@isempty, check);
    final_files = f(~filtered_ind);

    %// Do your final processing
    for i = 1:length(final_files)
        s = final_files(i);  %// Get the dir structure for a file that passed the ID check

        %// Create your structure now...
        %// ...
    end 
end

With the above code, we open the text file, then parse each string that's in the text file and place it into a cell array called IDs. Note here that the IDs are now all strings, so there's no need to do any conversions. After, for each ID we have, we search our filenames to see which files have this ID we're looking for. We filter out those filenames that don't have this ID, then we loop over each one of these files and create our structures. We do this for each ID that we have.


Just to demonstrate that this regexp stuff is working, as a small example, let's use the three filenames you have provided with your post. I've placed these names in a cell array, then I'll run lines 3 to 5 in the code I wrote, then I will filter out those filenames that don't contain the ID we're looking for:

filenames = {'1242349_blabla.wav'; 'fdp23424_asdf.wav'; 'o2349_0.wav'};
ID = 23424;
check = regexp(filenames, num2str(ID));
filtered_ind = cellfun(@isempty, check);
final_filenames = filenames(~filtered_ind);

final_filenames is a cell array our filenames that have our ID. We thus get:

final_filenames = 

    'fdp23424_asdf.wav'

Good luck!

1
votes

Regular expressions are definitely the most flexible and powerful solution. But, if your needs are simpler...you can get away with something simpler, like using wildcards in your dir command. Try something like this:

%get your file IDs from the input file
fid = fopen('input.txt');
input = textscan(fid, '%s', 'Delimiter', '\n');
IDs = input{1};

%loop over each string
myfilenames = {};
for idx = 1:length(IDs)
    %get all files build off the given ID
    fnames = dir(['somedir/*' IDs{idx} '*.wav']);  %wildcards!

    %gather the new filenames that match
    for Ifname=1:length(fnames)
        myfilenames{end+1}=fnames(Ifname).name;
    end
end