从路径字符串中提取直接子目录

时间:2010-04-30 20:32:27

标签: php string path extract relative-path

我需要从完整路径字符串中提取直接子目录的名称。

例如,假设我们有:

$str = "dir1/dir2/dir3/dir4/filename.ext";
$dir = "dir1/dir2";

然后$ str路径中相对于$ dir的子目录的名称将是“dir3”。请注意,$ dir的末尾永远不会有'/'。

所以功能应该是:

$subdir = getsubdir($str,$dir);
echo $subdir; // Outputs "dir3"

如果$ dir =“dir1”,则输出为“dir2”。如果$ dir =“dir1 / dir2 / dir3 / dir4”,则输出将为“”(空)。如果$ dir =“”那么输出将是“dir1”。等。

目前这就是我所拥有的,并且它有效(据我测试过)。我只是想知道是否有一种更简单的方法,因为我发现我使用了很多字符串函数。也许在一行中有一些神奇的正则表达式? (不幸的是,我对regexp并不太好。)

function getsubdir($str,$dir) {
    // Remove the filename
    $str = dirname($str);

    // Remove the $dir
    if(!empty($dir)){
        $str = str_replace($dir,"",$str);
    }

    // Remove the leading '/' if there is one
    $si = stripos($str,"/");
    if($si == 0){
        $str = substr($str,1);
    }

    // Remove everything after the subdir (if there is anything)
    $lastpart = strchr($str,"/");
    $str = str_replace($lastpart,"",$str);

    return $str;
}

正如你所看到的,为了处理一些奇怪的情况(输入中没有'/',空输入等),它有点hacky。我希望所有这些都是有道理的。欢迎任何帮助/建议。

更新(更改解决方案):

好吧 Alix Axel 让它发现了。这是他的解决方案,略微调整,以便它符合我的确切要求(例如:它必须返回一个字符串,只输出目录(而不是文件))

function getsubdir($str,$dir) {
    $str = dirname($str);
    $temp = array_slice(array_diff(explode('/', $str), explode('/', $dir)), 0, 1);
    return $temp[0];   
}

3 个答案:

答案 0 :(得分:4)

你走了:

function getSubDir($dir, $sub)
{
    return array_slice(array_diff(explode('/', $dir), explode('/', $sub)), 0, 1);
}

编辑 - 实施万无一失:

function getSubDirFoolproof($dir, $sub)
{
    /*
    This is the ONLY WAY we have to make SURE that the
    last segment of $dir is a file and not a directory.
    */
    if (is_file($dir))
    {
        $dir = dirname($dir);
    }

    // Is it necessary to convert to the fully expanded path?
    $dir = realpath($dir);
    $sub = realpath($sub);

    // Do we need to worry about Windows?
    $dir = str_replace('\\', '/', $dir);
    $sub = str_replace('\\', '/', $sub);

    // Here we filter leading, trailing and consecutive slashes.
    $dir = array_filter(explode('/', $dir));
    $sub = array_filter(explode('/', $sub));

    // All done!
    return array_slice(array_diff($dir, $sub), 0, 1);
}

答案 1 :(得分:2)

如何将整个事物分成数组:

$fullpath = explode("/", "dir1/dir2/dir3/dir4/filename.ext");
$fulldir  = explode("/", "dir1/dir2");

// Will result in array("dir1","dir2","dir3", "dir4", "filename.ext");
// and            array("dir1", "dir2");

然后您应该可以使用array_diff()

$remainder = array_diff($fullpath, $fulldir);

// Should return array("dir3", "dir4", "filename.ext");

然后,直接生孩子很容易:

echo $remainder[0];

我现在无法测试它,但它应该有效。

答案 2 :(得分:0)

这是一个类似的“短”解决方案,这次使用字符串函数而不是数组函数。如果没有从字符串中获取相应的部分,getsubdir将返回FALSEstrtr段是逃避百分比的快捷方式,对sscanf具有特殊意义。

function getsubdir($str, $dir) {
    return sscanf($str, strtr($dir, '%', '%%').'/%[^/]', $name) === 1 ? $name : FALSE;
}

快速测试,以便了解它的行为:

$str = "dir1/dir2/dir3/dir4/filename.ext";
var_dump(
    getSubDir($str, "dir1"),
    getSubDir($str, "dir1/dir2/dir3"),
    getSubDir($str, "cake")
);
// string(4) "dir2"
// string(4) "dir4"
// bool(false)