【问题标题】:How to check char array contain any char without loop in C++?如何在 C++ 中检查 char 数组是否包含任何没有循环的字符?
【发布时间】:2020-04-16 20:12:10
【问题描述】:

我正在使用 opendir 和 readdir 函数在给定目录中搜​​索包含 .txt 的文件名。

有什么方法可以在不使用循环的情况下通过函数测试certain extension? (目前我必须循环通过de-> d_filename 进行检查,但它们非常复杂,另外我尝试了de->d_type 但它没有返回扩展名)

另外这个函数是返回文件名的名字,我想要的结果是从头获取路径名,有没有类似de->d_fullfilepath?的函数return wchar_t*

这就是我所拥有的:

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);
    }
}

【问题讨论】:

  • new wchar_t(lpszFolder) 创建一个 single 字符,并将其初始化为值 lpszFolder。你有什么理由不使用std::wstring
  • 仅仅因为目录 API 使用字符数组和指针并不意味着您必须效仿。获得名称后,将其复制到 std::wstring 并使用糟糕的数组或字符指针完成。
  • 感谢 Mr.Someprogrammerdude 和 Mr.PaulMcKenzie,我试过了,它与 wstring 完美配合。
  • 更好的选择是使用&lt;filesystem&gt; library 中的类并让他们为您处理这些细节。在这种情况下,请查看std::filesystem::directory_iterator
  • 嗨,@Remy 先生,我以前见过文件系统,但我发现它与我需要的格式不同:wchar_t *: ` C:\\Users\\MYFOLDER\\Downloads\\ ` 所以我忽略了它:(((。现在我能了。谢谢你的建议!

标签: c++


【解决方案1】:

反向搜索的最佳 Libc 函数

你可以考虑strrchr

定位字符串中最后一次出现的字符 返回指向 C 字符串 str 中最后出现的字符的指针。
终止的空字符被认为是 C 字符串的一部分。因此,也可以定位它来检索指向字符串结尾的指针。


查找具有特定文件扩展名的文件的示例程序

#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;
}

主要用途

测试:

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

将查找所有带有“.txt”扩展名的文件

或者如果你想要一个特定的扩展,比如 ☠ :

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

【讨论】:

  • 哇。良好的 C++ 代码。现在我明白为什么这被赞成了。用法:using namespace std;(void)ext;reinterpret_cast &lt; wchar_t*&gt;(ent-&gt;d_name)string.h 和字符串函数,NULL。具有幻数大小的普通 C 数组。真的非常令人印象深刻。不知何故,无法从问题中回答“C++ 中没有循环”的部分。但是没问题。而且,不幸的是我无法在我的机器上测试它,因为它不使用 C++ 可移植语言元素。但我相信这个非常好的 C++ 代码。谢谢你的好答案。人们可以从中学到很多东西。
【解决方案2】:

在现代 C++ 中,您应该使用 std::algorithm library 中的算法来避免循环。这些算法可以防止错误使用循环导致的许多问题,主要是越界问题。

而且,C++ 可以处理具有基本数据类型 wchar_t 的“宽字符串”。您可以简单地使用std::wstring 而不是std::string

你应该从不使用普通的 C 样式数组或指向 char 或 wchar_t 的指针。这些很容易出错,实际上不应该使用它们。

即使您有带有“旧”“char*”字符串的遗留代码,也请将它们放入std::string 并在将来使用。

下一步:您不得对拥有的内存使用原始指针。您应该尽量避免使用指针,而应使用智能指针。而且你不应该在 C++ 中使用new。几乎不再需要它了。使用 STL 中的容器。

现在回到你原来的问题:

如何在 C++ 中检查 char 数组是否包含任何没有循环的字符?

是的,通过使用std::algorithms和迭代器

有什么方法可以在不使用循环的情况下通过函数测试某个扩展?

是的,std::filesystem 会帮助你。它具有您需要的所有功能,并且优于所有手工制作的解决方案。特别是还可以处理wchar_t和宽字符串std::wstring

在下面的代码中,我生成了一个示例函数,它返回一个std::vector,其中填充了具有给定字符串的指定目录中的所有完整文件路径。

#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;
}

这是许多可能的解决方案之一。如果我能更好地了解您的要求,这甚至可以进行优化。

我会更详细地解释这个功能。但是,因为反正没人会看这个,我节省了时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 2018-04-06
    • 2015-09-08
    • 1970-01-01
    • 2015-02-28
    • 2012-02-11
    相关资源
    最近更新 更多