Dang D. Khanh
Dang D. Khanh

Reputation: 1471

How to check char array contain any char without loop in C++?

I'm using the opendir and readdir functions to search for file names containing .txt in the given directory.

Is there any way I can test a certain extension via a function without using a loop? (currently I have to loop through de-> d_filename to check but they are quite complicated, in addition I tried de->d_type however it did not return the extension)

In addition, this function is returning the name of the file name, my desired result is to get the path name from the beginning, is there a function return wchar_t* similar to de->d_fullfilepath?

This is all I have :

DIR* dr = opendir(lpszFolder);
vector<const wchar_t*> names;  //get list file with extension .txt then push to this vector

if (dr == NULL)  // opendir returns NULL if couldn't open directory 
{
    printf("Could not open current directory");
    return {};
}

// Refer http://pubs.opengroup.org/onlinepubs/7990989775/xsh/readdir.html 
// for readdir() 
while ((de = readdir(dr)) != NULL)
{
    if (de->d_type ... 'txt') // function get just .txt file.
    {
        wchar_t* pwc =new wchar_t(lpszFolder);       //initialize new instance file path
        const size_t cSize = de->d_namlen + 1;       //get file len
        mbstowcs(pwc, de->d_name, cSize);            //combine thisfilepath + extension
        names.push_back(pwc);
    }
}

Upvotes: 1

Views: 390

Answers (2)

Antonin GAVREL
Antonin GAVREL

Reputation: 11219

Best Libc function to search reversely

You might consider strrchr

Locate last occurrence of character in string Returns a pointer to the last occurrence of character in the C string str.
The terminating null-character is considered part of the C string. Therefore, it can also be located to retrieve a pointer to the end of a string.


Sample Program to find files with specific file extension

#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <string>
#include <vector>

using namespace std;

const char *get_filename_ext(const char *filename) {
    const char *dot = strrchr(filename, '.');
    return (!dot || dot == filename) ? "" : dot + 1;
}

int main(int ac, char **av) {
    if (ac != 2)
        return 1;
    const char *lookup = (ac==3) ? av[2] : "txt";

    const char *lpszFolder = av[1];
    DIR* dr = opendir(lpszFolder);
    vector<const wchar_t*> names;  //get list file with extension .txt then push     to this vector

    if (dr == NULL)  // opendir returns NULL if couldn't open directory 
    {
        printf("Could not open current directory");
        return (1);
    }
    struct dirent *ent;
    uint32_t len = sizeof(((dirent*)0)->d_name);
    char ext[len];
    while ((ent = readdir (dr)) != NULL) {
        (void)ext;
        strncpy(ext, get_filename_ext(ent->d_name), len-1);
        if (!strcmp(lookup, ext))
            names.push_back(reinterpret_cast < wchar_t*>(ent->d_name));
    }

    closedir(dr);

    for (auto name : names)
        printf("%s", (char *)name);
    return 0;
}

Main Usage

Test with:

g++ a.cpp && ./a.out myfolder

will look for all files with ".txt" extensions

Or if you want a specific extension like ☠ :

g++ a.cpp && ./a.out myfolder ☠ 

Upvotes: 3

A M
A M

Reputation: 15277

In modern C++ you should use algorithms from the std::algorithm library to avoid loops. These algorithms prevent many possible problems from the wrong usage of loops, mostly out of bounds problems.

And, C++ can deal with "wide strings" with the base data type wchar_t. You can simply use std::wstring instead of std::string.

Any you should not and never use plain C-Style arrays or pointers to char or wchar_t. These are that error prone that they should really not be used.

Even if you have legacy code with "old" "char*"-strings, put them into a std::string and use those in the future.

Next: You MUST NOT use raw pointers for owned memory. You should try to avoid pointers in general and use smart pointers instead. And you should not use new in C++. There is nearly no need for it any longer. Use containers from the STL.

Now back to your original question:

How to check char array contain any char without loop in C++?

Yes, by using std::algorithmsand iterators

Is there any way I can test a certain extension via a function without using a loop?

Yes, ths std::filesystem will help you. It has all the functionality you need and is superior to all handcraftedt solutions. It can especially also deal with wchar_t and wide stringsstd::wstring

In the following code, I generated an example function that returns a std::vector filled with all fule file paths in a specified directory with a given string.

#include <iostream>
#include <string>
#include <filesystem>
#include <vector>
#include <algorithm>

// Name space alias for saving typing work
namespace fs = std::filesystem;

// A function, that gets a path to a director as wstring and returns all file paths as wstring with a given extension
std::vector<std::wstring> getFilesWithCertainExtension(const std::wstring& dirPath, const std::wstring& extension = L".txt") {

    // Put the wstring with path to the the directory in a generic path variable
     fs::path startPath{ dirPath };

    // Here we sill store all directory entries having a given extension
    std::vector<fs::directory_entry> filesInDirectory{};

    // Go thorugh the directory and copy all directory entries with a given extension int our vector
    std::copy_if(fs::directory_iterator(startPath), {}, std::back_inserter(filesInDirectory),
        [&](const fs::directory_entry& de) { return de.path().extension().wstring() == extension; });

    // The result of this function should be a vector of wstrings
    std::vector<std::wstring> result(filesInDirectory.size());

    // Convert directory entries to wstrings
    std::transform(filesInDirectory.begin(), filesInDirectory.end(), result.begin(),
        [](const fs::directory_entry& de) { return de.path().wstring(); });

    return result;
}

int main() {

    // Read all files from c:\\temp with the default extension ".txt"
    std::vector<std::wstring> files = getFilesWithCertainExtension(L"c:\\temp");

    // Show full paths to user
    for (const std::wstring& ws : files) std::wcout << ws << L"\n";

    return 0;
}

This is one of many possible solutions. This could even be optimized, if I would understand your requirements better.

I would explain the function in more detail. But, becuase anyway nobody will read this, I save the time.

Upvotes: 3

Related Questions