2010-04-30 45 views
1

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

例如,假设我们有:

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

然后$海峡路径相对于$目录中子目录的名称将是“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; 
} 

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

更新(改变溶液):

阿利克斯阿克塞尔有它发现的。这是他有轻微的调整解决方案,使其符合我的具体要求(如:它必须返回一个字符串,只有目录应该输出(而不是文件))

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

你内置PATHINFO()考虑使用? – 2010-04-30 20:47:12

+0

感谢您的建议。由于我只需要dirname部分(我可以直接从dirname函数获取),因此pathinfo在这种情况下是多余的。 – nebs 2010-05-01 16:00:24

回答

3

在这里你去:

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

嗯,为了简洁,必须得到+1。 :) – 2010-04-30 20:37:43

+0

@Pekka:你的回答更具描述性,我会鼓励它,但我必须“在大约3小时内回来”。 :P – 2010-04-30 20:41:00

+0

太棒了!你们很快!除了我将在原始消息中发布的一些具体内容之外,此功能完美无缺。 – nebs 2010-04-30 20:51:41

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]; 

我现在不能测试这个,但它应该可以工作。

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)