【问题标题】:Is there an equivalent for Glob in D Phobos?D Phobos 中是否有 Glob 的等价物?
【发布时间】:2016-08-06 20:08:40
【问题描述】:

在 python 中,我可以使用 glob 来搜索路径模式。例如:

import glob
for entry in glob.glob("/usr/*/python*"):
    print(entry)

会打印这个:

/usr/share/python3
/usr/share/python3-plainbox
/usr/share/python
/usr/share/python-apt
/usr/include/python3.5m
/usr/bin/python3
/usr/bin/python3m
/usr/bin/python2.7
/usr/bin/python
/usr/bin/python3.5
/usr/bin/python3.5m
/usr/bin/python2
/usr/lib/python3
/usr/lib/python2.7
/usr/lib/python3.5

我如何glob 或在 D 中创建一个等效的 glob?

-----2017 年 9 月 12 日更新------

我写了一个小D模块在D中做Glob:https://github.com/workhorsy/d-glob

【问题讨论】:

  • It seems 表示使用 D 的标准库只能进行路径过滤(例如 dirEntries)。值得提出增强请求吗?

标签: d glob phobos


【解决方案1】:

如果你只在 Posix 系统上工作,你可以直接调用glob.h。下面是一个简单的示例,展示了与 Posix API 交互是多么容易:

void main()
{
    import std.stdio;
    import glob : glob; 
    foreach(entry; glob("/usr/*/python*"))
        writeln(entry);
}

你可以编译这个,例如使用rdmd main.d(rdmd 进行简单的依赖管理)或dmd main.d glob.d,它会在我的机器上产生与您类似的输出。

glob.ddstep 生成,并通过方便的 D 样式包装器(第一个函数)进行了增强。请注意,这并不完美,更好的方法是公开一个范围 API,而不是分配整个数组。

/* Copyright (C) 1991-2016 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

string[] glob(string pattern)
{
    import std.string;
    string[] results;
    glob_t glob_result;
    glob(pattern.toStringz, 0, null, &glob_result);
    for (uint i = 0; i < glob_result.gl_pathc; i++)
    {
        results ~= glob_result.gl_pathv[i].fromStringz().idup;
    }

    globfree(&glob_result);
    return results;
}

import core.stdc.config;

extern (C):

enum _GLOB_H = 1;

/* We need `size_t' for the following definitions.  */
alias c_ulong __size_t;
alias c_ulong size_t;

/* The GNU CC stddef.h version defines __size_t as empty.  We need a real
   definition.  */

/* Bits set in the FLAGS argument to `glob'.  */
enum GLOB_ERR = 1 << 0; /* Return on read errors.  */
enum GLOB_MARK = 1 << 1; /* Append a slash to each name.  */
enum GLOB_NOSORT = 1 << 2; /* Don't sort the names.  */
enum GLOB_DOOFFS = 1 << 3; /* Insert PGLOB->gl_offs NULLs.  */
enum GLOB_NOCHECK = 1 << 4; /* If nothing matches, return the pattern.  */
enum GLOB_APPEND = 1 << 5; /* Append to results of a previous call.  */
enum GLOB_NOESCAPE = 1 << 6; /* Backslashes don't quote metacharacters.  */
enum GLOB_PERIOD = 1 << 7; /* Leading `.' can be matched by metachars.  */
enum GLOB_MAGCHAR = 1 << 8; /* Set in gl_flags if any metachars seen.  */
enum GLOB_ALTDIRFUNC = 1 << 9; /* Use gl_opendir et al functions.  */
enum GLOB_BRACE = 1 << 10; /* Expand "{a,b}" to "a" "b".  */
enum GLOB_NOMAGIC = 1 << 11; /* If no magic chars, return the pattern.  */
enum GLOB_TILDE = 1 << 12; /* Expand ~user and ~ to home directories. */
enum GLOB_ONLYDIR = 1 << 13; /* Match only directories.  */
enum GLOB_TILDE_CHECK = 1 << 14; /* Like GLOB_TILDE but return an error
                      if the user name is not available.  */
enum __GLOB_FLAGS = GLOB_ERR | GLOB_MARK | GLOB_NOSORT | GLOB_DOOFFS | GLOB_NOESCAPE | GLOB_NOCHECK | GLOB_APPEND | GLOB_PERIOD | GLOB_ALTDIRFUNC | GLOB_BRACE | GLOB_NOMAGIC | GLOB_TILDE | GLOB_ONLYDIR | GLOB_TILDE_CHECK;

/* Error returns from `glob'.  */
enum GLOB_NOSPACE = 1; /* Ran out of memory.  */
enum GLOB_ABORTED = 2; /* Read error.  */
enum GLOB_NOMATCH = 3; /* No matches found.  */
enum GLOB_NOSYS = 4; /* Not implemented.  */

/* Previous versions of this file defined GLOB_ABEND instead of
   GLOB_ABORTED.  Provide a compatibility definition here.  */

/* Structure describing a globbing run.  */

struct glob_t
{
    __size_t gl_pathc; /* Count of paths matched by the pattern.  */
    char** gl_pathv; /* List of matched pathnames.  */
    __size_t gl_offs; /* Slots to reserve in `gl_pathv'.  */
    int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR.  */

    /* If the GLOB_ALTDIRFUNC flag is set, the following functions
       are used instead of the normal file access functions.  */
    void function (void*) gl_closedir;

    void* function (void*) gl_readdir;

    void* function (const(char)*) gl_opendir;

    int function (const(char)*, void*) gl_lstat;
    int function (const(char)*, void*) gl_stat;
}

/* If the GLOB_ALTDIRFUNC flag is set, the following functions
   are used instead of the normal file access functions.  */

/* Do glob searching for PATTERN, placing results in PGLOB.
   The bits defined above may be set in FLAGS.
   If a directory cannot be opened or read and ERRFUNC is not nil,
   it is called with the pathname that caused the error, and the
   `errno' value from the failing call; if it returns non-zero
   `glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
   If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
   Otherwise, `glob' returns zero.  */

int glob (
    const(char)* __pattern,
    int __flags,
    int function (const(char)*, int) __errfunc,
    glob_t* __pglob);

/* Free storage allocated in PGLOB by a previous `glob' call.  */
void globfree (glob_t* __pglob);

【讨论】:

  • 尽管这不是使用 Phobos,但它看起来是一个足够好的解决方案。谢谢。
  • 不要忘记file an enhancement request 火卫一 ;-)
【解决方案2】:

以上答案都没有与 Windows 和 Linux 上的 Glob 100% 相同。所以我做了一个小的 D 模块,它以正确的方式运行 Glob。希望人们觉得它有用:

https://github.com/workhorsy/d-glob

import std.stdio : stdout;
import glob : glob;

foreach (entry ; glob("/usr/*/python*")) {
    stdout.writefln("%s", entry);
}

【讨论】:

    【解决方案3】:

    也许你正在寻找std.file.dirEntries()

    以下是文档中的示例:

    // Iterate over all D source files in current directory and all its
    // subdirectories
    auto dFiles = dirEntries("","*.{d,di}",SpanMode.depth);
    foreach(d; dFiles)
        writeln(d.name);
    

    【讨论】:

    • 这不太行。 glob 模式似乎不适用于跨目录。
    • dirEntries 是一个范围,所以你可以过滤它,但它当然会遍历所有文件:/
    【解决方案4】:

    基本上,您不需要用头文件、C 等语言做所有这些复杂的事情。这应该做的事情:

    auto dirIter = dirEntries("/usr", "*/python*", SpanMode.shallow);
    foreach(dirFile; dirIter) {
        // Process the result as needed
    

    【讨论】:

    • SpanMode.shallow 只会迭代一个级别 - 因此您的示例不会返回任何文件。参见例如this DPaste。不幸的是,还没有简单的方法可以用 D 做到这一点:/
    • 我猜OP想列出所有以python开头并位于/usr/*的目录,不是吗?)
    • 是的,但是带有usrshallow 的目录条目只会看起来一层深(例如/usr/share
    猜你喜欢
    • 2012-01-14
    • 1970-01-01
    • 2011-07-29
    • 2013-06-21
    • 2014-01-09
    • 2012-02-18
    • 2014-05-02
    • 1970-01-01
    相关资源
    最近更新 更多