PHP에서 파일 시스템 경로 문자열을 결합하는 방법은 무엇입니까?
PHP에 지능적으로 경로 문자열을 결합하는 내장 기능이 있습니까? "abc / de /"및 "/fg/x.php"를 인수로 지정한 함수는 "abc / de / fg / x.php"를 반환해야합니다. "abc / de"및 "fg / x.php"를 해당 함수의 인수로 사용하여 동일한 결과를 제공해야합니다.
그렇지 않은 경우 사용 가능한 수업이 있습니까? 경로를 분할하거나 일부를 제거하는데도 유용 할 수 있습니다. 무언가를 작성했다면 여기에서 코드를 공유 할 수 있습니까?
항상 "/"를 사용해도 괜찮습니다. 저는 Linux 전용으로 코딩하고 있습니다.
Python에는 os.path.join()
, 이것은 훌륭합니다.
이것은 인기있는 질문 인 것 같고 주석이 "기능 제안"또는 "버그 보고서"로 채워져 있기 때문에 ...이 코드 조각이 수행하는 모든 작업은 슬래시를 중복하지 않고 두 문자열을 슬래시로 결합하는 것입니다. 그게 다야. 그 이상도 이하도 아닌. 하드 디스크의 실제 경로를 평가하지 않으며 실제로 시작 슬래시를 유지하지 않습니다 (필요한 경우 다시 추가하십시오. 적어도이 코드는 슬래시 시작 없이 항상 문자열 을 반환하는지 확인할 수 있습니다 ).
join('/', array(trim("abc/de/", '/'), trim("/fg/x.php", '/')));
최종 결과는 항상 시작 또는 끝에 슬래시가없고 내부에 이중 슬래시가없는 경로입니다. 그것으로 기능을 자유롭게 만드십시오.
편집 : 위의 스 니펫에 대한 멋진 유연한 함수 래퍼가 있습니다. 배열 또는 개별 인수로 원하는만큼 경로 스 니펫을 전달할 수 있습니다.
function joinPaths() {
$args = func_get_args();
$paths = array();
foreach ($args as $arg) {
$paths = array_merge($paths, (array)$arg);
}
$paths = array_map(create_function('$p', 'return trim($p, "/");'), $paths);
$paths = array_filter($paths);
return join('/', $paths);
}
echo joinPaths(array('my/path', 'is', '/an/array'));
//or
echo joinPaths('my/paths/', '/are/', 'a/r/g/u/m/e/n/t/s/');
:영형)
function join_paths() {
$paths = array();
foreach (func_get_args() as $arg) {
if ($arg !== '') { $paths[] = $arg; }
}
return preg_replace('#/+#','/',join('/', $paths));
}
내 솔루션은 Python os.path.join이 작동하는 방식과 더 간단하고 유사합니다.
이 테스트 케이스를 고려하십시오
array my version @deceze @david_miller @mark
['',''] '' '' '/' '/'
['','/'] '/' '' '/' '/'
['/','a'] '/a' 'a' '//a' '/a'
['/','/a'] '/a' 'a' '//a' '//a'
['abc','def'] 'abc/def' 'abc/def' 'abc/def' 'abc/def'
['abc','/def'] 'abc/def' 'abc/def' 'abc/def' 'abc//def'
['/abc','def'] '/abc/def' 'abc/def' '/abc/def' '/abc/def'
['','foo.jpg'] 'foo.jpg' 'foo.jpg' '/foo.jpg' '/foo.jpg'
['dir','0','a.jpg'] 'dir/0/a.jpg' 'dir/a.jpg' 'dir/0/a.jpg' 'dir/0/a.txt'
@deceze의 함수는 Unix 절대 경로로 시작하는 경로에 합류하려고 할 때 /를 선두로 유지하지 않습니다 joinPaths('/var/www', '/vhosts/site');
.
function unix_path() {
$args = func_get_args();
$paths = array();
foreach($args as $arg) {
$paths = array_merge($paths, (array)$arg);
}
foreach($paths as &$path) {
$path = trim($path, '/');
}
if (substr($args[0], 0, 1) == '/') {
$paths[0] = '/' . $paths[0];
}
return join('/', $paths);
}
내 테이크 :
function trimds($s) {
return rtrim($s,DIRECTORY_SEPARATOR);
}
function joinpaths() {
return implode(DIRECTORY_SEPARATOR, array_map('trimds', func_get_args()));
}
에 대해 익명 함수를 사용 trimds
했지만 이전 버전의 PHP에서는이를 지원하지 않습니다.
예:
join_paths('a','\\b','/c','d/','/e/','f.jpg'); // a\b\c\d\e\f.jpg (on Windows)
업데이트 됨 2013 년 4 월 2014 년 3 월 2018 년 5 월 :
function join_paths(...$paths) {
return preg_replace('~[/\\\\]+~', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, $paths));
}
이것은 OS와 일치하도록 모든 슬래시를 수정하고 선행 슬래시를 제거하지 않으며 연속으로 여러 슬래시를 정리합니다.
이 파일 / 디렉토리가 존재 알고 있다면 , 당신은 여분의 슬래시 (즉 불필요 할 수 있음), 다음 전화를 추가 할 수 있습니다 realpath 즉,
realpath(join('/', $parts));
물론 이것은 파이썬 버전과 완전히 같지는 않지만 많은 경우에 충분할 수 있습니다.
대안은 implode()
및 explode()
.
$a = '/a/bc/def/';
$b = '/q/rs/tuv/path.xml';
$path = implode('/',array_filter(explode('/', $a . $b)));
echo $path; // -> a/bc/def/q/rs/tuv/path.xml
경로의 일부를 얻으려면 pathinfo http://nz2.php.net/manual/en/function.pathinfo.php를 사용할 수 있습니다.
@deceze의 응답에 참여하는 것은 괜찮아 보입니다.
이것을 공격하는 다른 방법 :
function joinPaths() {
$paths = array_filter(func_get_args());
return preg_replace('#/{2,}#', '/', implode('/', $paths));
}
아래 솔루션은 @RiccardoGalli가 제안한 논리를 사용하지만 DIRECTORY_SEPARATOR
@Qix 및 @ FélixSaparelli가 제안한대로 상수 자체를 사용하도록 개선 되었으며, 더 중요한 것은 최종에 나타나는 공간 전용 폴더 이름을 피하기 위해 주어진 요소 를 트리밍 하는 것입니다. 경로 (제 경우에는 요구 사항이었습니다).
preg_replace()
패턴 내부의 디렉토리 구분 기호 이스케이프와 관련하여 알 수 있듯이 preg_quote()
작업을 잘 수행하는 기능을 사용했습니다 .
또한 여러 구분 기호 만 교체 합니다 (RegExp 수량 자 {2,}
).
// PHP 7.+
function paths_join(string ...$parts): string {
$parts = array_map('trim', $parts);
$path = [];
foreach ($parts as $part) {
if ($part !== '') {
$path[] = $part;
}
}
$path = implode(DIRECTORY_SEPARATOR, $path);
return preg_replace(
'#' . preg_quote(DIRECTORY_SEPARATOR) . '{2,}#',
DIRECTORY_SEPARATOR,
$path
);
}
이것은 deceze가 게시 한 함수의 수정 된 버전입니다. 이 변경없이 joinPaths ( '', 'foo.jpg')는 '/foo.jpg'가됩니다.
function joinPaths() {
$args = func_get_args();
$paths = array();
foreach ($args as $arg)
$paths = array_merge($paths, (array)$arg);
$paths2 = array();
foreach ($paths as $i=>$path)
{ $path = trim($path, '/');
if (strlen($path))
$paths2[]= $path;
}
$result = join('/', $paths2); // If first element of old path was absolute, make this one absolute also
if (strlen($paths[0]) && substr($paths[0], 0, 1) == '/')
return '/'.$result;
return $result;
}
이것은 꽤 잘 작동하는 것 같고 합리적으로 깔끔하게 보입니다.
private function JoinPaths() {
$slash = DIRECTORY_SEPARATOR;
$sections = preg_split(
"@[/\\\\]@",
implode('/', func_get_args()),
null,
PREG_SPLIT_NO_EMPTY);
return implode($slash, $sections);
}
찾은 최상의 솔루션 :
function joinPaths($leftHandSide, $rightHandSide) {
return rtrim($leftHandSide, '/') .'/'. ltrim($rightHandSide, '/');
}
참고 : user89021의 댓글에서 복사 됨
Python에서 영감을 얻은 우아한 PHP 한 줄 방법으로 경로를 연결합니다.
이 코드는 불필요한 배열을 사용하지 않습니다.
다중 플랫폼
function os_path_join(...$parts) {
return preg_replace('#'.DIRECTORY_SEPARATOR.'+#', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, array_filter($parts)));
}
Unix 기반 시스템
function os_path_join(...$parts) {
return preg_replace('#/+#', '/', implode('/', array_filter($parts)));
}
REST 매개 변수가없는 Unix 기반 시스템 (명시적인 PEP8 철학을 존중하지 않음) :
function os_path_join() {
return preg_replace('#/+#', '/', implode('/', array_filter(func_get_args())));
}
용법
$path = os_path_join("", "/", "mydir/", "/here/");
보너스 : 정말로 파이썬 os.path.join ()을 따르고 싶다면. 첫 번째 인수가 필요합니다.
function os_path_join($path=null, ...$paths) {
if (!is_null($path)) {
throw new Exception("TypeError: join() missing 1 required positional argument: 'path'", 1);
}
$path = rtrim($path, DIRECTORY_SEPARATOR);
foreach ($paths as $key => $current_path) {
$paths[$key] = $paths[$key] = trim($current_path, DIRECTORY_SEPARATOR);
}
return implode(DIRECTORY_SEPARATOR, array_merge([$path], array_filter($paths)));
}
원한다면 os.path.join () 소스를 확인하십시오 : https://github.com/python/cpython/blob/master/Lib/ntpath.py
경고 :이 솔루션은 URL에 적합하지 않습니다.
다음은 Nodepath.resolve
처럼 동작하는 함수입니다 .
function resolve_path() {
$working_dir = getcwd();
foreach(func_get_args() as $p) {
if($p === null || $p === '') continue;
elseif($p[0] === '/') $working_dir = $p;
else $working_dir .= "/$p";
}
$working_dir = preg_replace('~/{2,}~','/', $working_dir);
if($working_dir === '/') return '/';
$out = [];
foreach(explode('/',rtrim($working_dir,'/')) as $p) {
if($p === '.') continue;
if($p === '..') array_pop($out);
else $out[] = $p;
}
return implode('/',$out);
}
테스트 사례 :
resolve_path('/foo/bar','./baz') # /foo/bar/baz
resolve_path('/foo/bar','/tmp/file/') # /tmp/file
resolve_path('/foo/bar','/tmp','file') # /tmp/file
resolve_path('/foo//bar/../baz') # /foo/baz
resolve_path('/','foo') # /foo
resolve_path('/','foo','/') # /
resolve_path('wwwroot', 'static_files/png/', '../gif/image.gif')
# __DIR__.'/wwwroot/static_files/gif/image.gif'
Ricardo Galli의 위대한 대답에서 프로토콜 접두사를 죽이는 것을 피하기 위해 약간의 개선이 있습니다.
아이디어는 하나의 인수에서 프로토콜의 존재를 테스트하고 결과로 유지하는 것입니다. 경고 : 이것은 순진한 구현입니다!
예를 들면 :
array("http://domain.de","/a","/b/")
결과 (프로토콜 유지)
"http://domain.de/a/b/"
(살인 프로토콜) 대신
"http:/domain.de/a/b/"
그러나 http://codepad.org/hzpWmpzk 에는 더 나은 코드 작성 기술이 필요합니다.
나는 리카르도의 대답 을 좋아하고 그것이 최선의 대답이라고 생각합니다.
I am using it to join paths in url building, but with one small change to handle protocols' double slash:
function joinPath () {
$paths = array();
foreach (func_get_args() as $arg) {
if ($arg !== '') { $paths[] = $arg; }
}
// Replace the slash with DIRECTORY_SEPARATOR
$paths = preg_replace('#/+#', '/', join('/', $paths));
return preg_replace('#:/#', '://', $paths);
}
OS-independent version based on the answer by mpen but encapsulated into a single function and with the option to add a trailing path separator.
function joinPathParts($parts, $trailingSeparator = false){
return implode(
DIRECTORY_SEPARATOR,
array_map(
function($s){
return rtrim($s,DIRECTORY_SEPARATOR);
},
$parts)
)
.($trailingSeparator ? DIRECTORY_SEPARATOR : '');
}
Or for you one-liner lovers:
function joinPathParts($parts, $trailingSeparator = false){
return implode(DIRECTORY_SEPARATOR, array_map(function($s){return rtrim($s,DIRECTORY_SEPARATOR);}, $parts)).($trailingSeparator ? DIRECTORY_SEPARATOR : '');
}
Simply call it with an array of path parts:
// No trailing separator - ex. C:\www\logs\myscript.txt
$logFile = joinPathParts([getcwd(), 'logs', 'myscript.txt']);
// Trailing separator - ex. C:\www\download\images\user1234\
$dir = joinPathParts([getcwd(), 'download', 'images', 'user1234'], true);
function path_combine($paths) {
for ($i = 0; $i < count($paths); ++$i) {
$paths[$i] = trim($paths[$i]);
}
$dirty_paths = explode(DIRECTORY_SEPARATOR, join(DIRECTORY_SEPARATOR, $paths));
for ($i = 0; $i < count($dirty_paths); ++$i) {
$dirty_paths[$i] = trim($dirty_paths[$i]);
}
$unslashed_paths = array();
for ($i = 0; $i < count($dirty_paths); ++$i) {
$path = $dirty_paths[$i];
if (strlen($path) == 0) continue;
array_push($unslashed_paths, $path);
}
$first_not_empty_index = 0;
while(strlen($paths[$first_not_empty_index]) == 0) {
++$first_not_empty_index;
}
$starts_with_slash = $paths[$first_not_empty_index][0] == DIRECTORY_SEPARATOR;
return $starts_with_slash
? DIRECTORY_SEPARATOR . join(DIRECTORY_SEPARATOR, $unslashed_paths)
: join(DIRECTORY_SEPARATOR, $unslashed_paths);
}
Example usage:
$test = path_combine([' ', '/cosecheamo', 'pizze', '///// 4formaggi', 'GORGONZOLA']);
echo $test;
Will output:
/cosecheamo/pizze/4formaggi/GORGONZOLA
I liked several solutions presented. But those who does replacing all '/+' into '/' (regular expressions) are forgetting that os.path.join() from python can handle this kind of join:
os.path.join('http://example.com/parent/path', 'subdir/file.html')
Result: 'http://example.com/parent/path/subdir/file.html'
참고URL : https://stackoverflow.com/questions/1091107/how-to-join-filesystem-path-strings-in-php
'Nice programing' 카테고리의 다른 글
커서를 특정 행과 열로 이동하려면 어떻게합니까? (0) | 2020.11.09 |
---|---|
Lisp의 유연성에 대한 실제적인 예? (0) | 2020.11.09 |
클래스가 키 값 코딩을 준수하지 않습니다. (0) | 2020.11.09 |
특정 좌표 근처의 특정 장소를 검색하는 Google지도 URL을 형성합니다. (0) | 2020.11.09 |
두 개의 날짜 시간을 비교할 때 밀리 초 무시 (0) | 2020.11.09 |