2012-10-28 8 views
43

Czy istnieje istniejąca funkcja łączenia ścieżek?Funkcja łączenia ścieżek?

wiem, że nie jest to trudne do wykonania, ale ... oprócz dbania o spływu / (lub \) to muszę dbać o wykrywanie formatu ścieżka właściwa OS (tzn czy piszemy C:\dir\file lub /dir/file) .

Tak jak powiedziałem, wierzę, że wiem, jak to wdrożyć; pytanie brzmi: czy powinienem to zrobić? Czy ta funkcjonalność istnieje już w istniejącym pakiecie R?

Odpowiedz

74

Tak file.path()

R> file.path("usr", "local", "lib") 
[1] "usr/local/lib" 
R> 

Jest też równie użyteczny system.path() plików w pakiecie:

R> system.file("extdata", "date_time_zonespec.csv", package="RcppBDT") 
[1] "/usr/local/lib/R/site-library/RcppBDT/extdata/date_time_zonespec.csv" 
R> 

który dostanie plik extdata/date_time_zonespec.csv niezależnie od

  1. gdzie pakiet jest zainstalowany i
  2. OS

który jest bardzo przydatny. Na koniec istnieje również pewna wartość: jeśli nalegasz na ręczne wykonanie.

+1

Świetna odpowiedź. Ale funkcja nie zajmuje się końcowym "/", więc 'file.path ("/home/user/"," project ")' powoduje niepoprawne '/ home/user // project'. Czy istnieje inna funkcja, czy też powinienem to zrobić sam (choćby trywialnie)? –

+0

Otrzymasz, jeśli zaczniesz od pustego ciągu: 'file.path (" "," home "," user "," project ")' produkuje '"/home/user/project "' –

+2

Zwróć uwagę, że '/ home/user // project' i '/ home/user/project' są poprawne w systemie Unix. Na jakim systemie operacyjnym jesteś? – flodel

2

Jeśli ktoś chce, to jest moja własna funkcja path.cat. Jego funkcjonalność jest porównywalna z Pythonem os.path.join z dodatkowym cukrem, który interpretuje ...

Za pomocą tej funkcji można konstruować ścieżki hierarchicznie, ale w przeciwieństwie do file.path, użytkownik pozostawia możliwość nadpisania hierarchii, umieszczając bezwzględną ścieżkę. Jako dodatek do cukru może umieścić "..." wszędzie, gdzie mu się podoba, z oczywistym znaczeniem.

np.

  • path.cat("/home/user1","project/data","../data2") yelds /home/user1/project/data2

  • path.cat("/home/user1","project/data","/home/user2/data") yelds /home/user2/data

Funkcja działa tylko z ukośniki jako separator ścieżki, który jest w porządku, ponieważ R przejrzyście tłumaczy je na ukośniki na komputerze z systemem Windows.

library("iterators") # After writing this function I've learned, that iterators are very inefficient in R. 
library("itertools") 

#High-level function that inteligentely concatenates paths given in arguments 
#The user interface is the same as for file.path, with the exception that it understands the path ".." 
#and it can identify relative and absolute paths. 
#Absolute paths starts comply with "^\/" or "^\d:\/" regexp. 
#The concatenation starts from the last absolute path in arguments, or the first, if no absolute paths are given. 
path.cat<-function(...) 
{ 
    elems<-list(...) 
    elems<-as.character(elems) 
    elems<-elems[elems!='' && !is.null(elems)] 
    relems<-rev(elems) 
    starts<-grep('^[/\\]',relems)[1] 
    if (!is.na(starts) && !is.null(starts)) 
    { 
    relems<-relems[1:starts] 
    } 
    starts<-grep(':',relems,fixed=TRUE) 
    if (length(starts)==0){ 
    starts=length(elems)-length(relems)+1 
    }else{ 
    starts=length(elems)-starts[[1]]+1} 
    elems<-elems[starts:length(elems)] 
    path<-do.call(file.path,as.list(elems)) 
    elems<-strsplit(path,'[/\\]',FALSE)[[1]] 
    it<-ihasNext(iter(elems)) 
    out<-rep(NA,length(elems)) 
    i<-1 
    while(hasNext(it)) 
    { 
    item<-nextElem(it) 
    if(item=='..') 
    { 
     i<-i-1 
    } else if (item=='' & i!=1) { 
     #nothing 
    } else { 
     out[i]<-item 
     i<-i+1 
    } 
    } 
    do.call(file.path,as.list(out[1:i-1])) 
} 
+1

Jest to wykonywane przez normalizePath() –

+1

Super komentarz, ale jest ważna różnica:' normalizePath() 'wymaga, aby ścieżka była rzeczywiście obecna na serwerze R. To nie zawsze może być pożądane. Dla mnie jest to ważna różnica. Instrukcja OTOH mówi, że 'normalizePath()' konwertuje krótkie nazwy na długie w systemie Windows. –

Powiązane problemy