Napisz program do wyświetlania katalogu domku na drzewie

9

Biorąc pod uwagę katalog (taki jak C:/), podany ze standardowego wejścia lub odczytany z pliku, stwórz drzewo katalogów, z każdym wcięciem pliku / folderu na podstawie jego głębokości.

Przykład

Jeśli mam C:/dysk, który zawiera tylko dwa foldery fooi bar, i barjest pusty, gdy foozawiera baz.txt, wówczas uruchomiony z wejściem C:/produkuje:

C:/
    bar/
    foo/
        baz.txt

podczas pracy z nakładem C:/foo/powinien produkować

foo/
    baz.txt

Ponieważ jest to kodegolf, wygrywa najmniejsza liczba bajtów. Rozszerzenia plików (takie jak baz.txt) są opcjonalne. Dodatkowe uwagi: ukryte pliki można zignorować, katalogi muszą faktycznie istnieć, można założyć, że pliki nie zawierają znaków niedrukowalnych ani nowych wierszy, ale wszystkie inne znaki ASCII do wydruku są w porządku (nazwy plików ze spacjami muszą być obsługiwane). Dane wyjściowe można zapisać do pliku lub standardowego wyjścia. Wcięcia mogą składać się ze znaku tabulacji lub 4 spacji.

Mathime
źródło
1
Dodatkowa uwaga: to pytanie jest źle sformatowane, dlatego mile widziane byłoby sformatowanie.
Mathime,
Czy języki, które nie mają dostępu do plików, są automatycznie dyskwalifikowane?
Leaky Nun
Jakie nazwy plików muszą być obsługiwane? Pliki ze spacjami w swoich nazwach? Z nowymi liniami? Z drukowanymi postaciami? Co z ukrytymi plikami (zaczynając od .)?
Klamka
1
@LeakyNun Dane wyjściowe pytania referencyjnego to tablica tablic. To pytanie wymaga przedstawienia drzewa katalogów do wydrukowania na standardowe wyjście.
Mathime,
1
Czy wejście może być parametrem ciągu funkcji?
mbomb007

Odpowiedzi:

10

bash, 61 58 54 bajtów

find "$1" -exec ls -Fd {} \;|perl -pe's|.*?/(?!$)|  |g'

Pobiera dane wejściowe jako argument wiersza poleceń, dane wyjściowe w STDOUT.

Zauważ, że spacje na końcu przed |gznakiem są w rzeczywistości znakiem tabulacji (SE konwertuje je na spacje podczas wyświetlania postów).

find              crawl directory tree recursively
"$1"              starting at the input directory
-exec             and for each file found, execute...
ls -Fd {} \;      append a trailing slash if it's a directory (using -F of ls)
|perl -pe         pipe each line to perl
'
s|                replace...
.*?/              each parent directory in the file's path...
(?!$)             that doesn't occur at the end of the string...
|    |            with a tab character...
g                 globally
'

Dzięki @Dennis za 4 bajty!

Klamka
źródło
2

Dyalog APL , 48 bajtów

(⊂∘⊃,1↓'[^\\]+\\'⎕R'    ')r[⍋↑r←⎕SH'dir/s/b ',⍞]

monit o wprowadzenie znaku

'dir/s/b ', poprzedzać tekst

⎕SH wykonać w powłoce

r←przechowywać w r

zrobić listę ciągów znaków w macierz znaków

wskaźniki do sortowania rosnącego

r[... ]zmienić kolejność r [posortowane]

(... )na standardowym poleceniu poza powłoką wykonaj:

'[^\\]+\\'⎕R' ' regex zastępuje zakończone odwrotnym ukośnikiem przebiegi nie odwrotnych ukośników czterema spacjami

1↓ upuść pierwszą linię

⊂∘⊃, dodaj załączony pierwszy [wiersz]

Wynik wprowadzenia „\ tmp” do monitu zaczyna się na moim komputerze w następujący sposób:

C:\tmp\12u64
            keyboards64.msi
            netfx64.exe
            setup.exe
            setup_64_unicode.msi
            setup_dotnet_64.msi
        AdamsReg.reg
        AdamsReg.zip
        qa.dws
        ride-experimental
            win32
                d3dcompiler_47.dll
                icudtl.dat
                libEGL.dll

Adám
źródło
Czy katalogi nie powinny zawierać znaków końcowych \?
Neil
2

SML , 176 bajtów

open OS.FileSys;val! =chDir;fun&n w=(print("\n"^w^n);!n;print"/";c(openDir(getDir()))(w^"\t");!"..")and c$w=case readDir$of SOME i=>(&i w handle _=>();c$w)|x=>()fun%p=(&p"";!p)

Deklaruje (między innymi) funkcję, %która przyjmuje ciąg znaków jako argument. Zadzwoń z % "C:/Some/Path";lub % (getDir());do bieżącego katalogu.

Używam normalnie raczej funkcjonalnie używanego języka StandardML, którego FileSys-Bibliotekę odkryłem po przeczytaniu tego wyzwania.

Znaki specjalne !, &, $i %nie mają szczególnego znaczenia w samym języku, a są po prostu wykorzystywane jako identyfikatory; nie można ich jednak łączyć ze standardowymi identyfikatorami alfanumerycznymi, co pozwala pozbyć się całkiem potrzebnych spacji.

open OS.FileSys;
val ! = chDir;                       define ! as short cut for chDir

fun & n w = (                        & is the function name
                                     n is the current file or directory name
                                     w is a string containing the tabs
    print ("\n"^w^n);                ^ concatenates strings
    ! n;                             change in the directory, this throws an 
                                     exception if n is a file name
    print "/";                       if we are here, n is a directory so print a /
    c (openDir(getDir())) (w^"\t");  call c with new directory and add a tab to w
                                     to print the contents of the directory n
    ! ".."                           we're finished with n so go up again
)
and c $ w =                          'and' instead of 'fun' must be used 
                                     because '&' and 'c' are mutual recursive
                                     $ is a stream of the directory content
    case readDir $ of                case distinction whether any files are left
        SOME i => (                  yes, i is the file or directory name
            & i w handle _ => ();    call & to print i an check whether it's a 
                                     directory or not, handle the thrown exception 
            c $ w )                  recursively call c to check for more files in $
        | x    => ()                 no more files, we are finished

fun % p = (                          % is the function name, 
                                     p is a string containing the path
    & p "";                          call & to print the directory specified by p
                                     and recursively it's sub-directories
    ! p                              change back to path p due to the ! ".." in &
)

Może być skompilowany w ten sposób z SML / NJ lub z Moscow ML * przez prefiks z load"OS";.

* Zobacz mosml.org, nie można opublikować więcej niż 2 linków.

Laikoni
źródło
1

C # (.NET Core) , 222 bajty

namespace System.IO{class P{static int n;static void Main(String[]a){Console.WriteLine(new string('\t',n++)+Path.GetFileName(a[0]));try{foreach(var f in Directory.GetFileSystemEntries(a[0])){a[0]=f;Main(a);}}catch{}n--;}}}

Wypróbuj online!


Ungolf:

using System.IO;
using System;

class P
{
    static int n=0;
    static void Main(String[] a)
    {
        for (int i=0;i<n;i++) Console.Write("\t");
        Console.WriteLine(Path.GetFileName(a[0]));
        n++;

        if(Directory.Exists(a[0]))
            foreach (String f in Directory.GetFileSystemEntries(a[0]))
                Main(new String[]{f});
        n--;
    }
}

Po raz pierwszy w historii zawróciłem Mainfunkcję!

Wierzę, że osoba, która ma świeższą wiedzę na temat C #, może bardziej grać w golfa, ponieważ przez pewien czas nie programowałem na C #!

sergiol
źródło
0

PHP, 180 bajtów

  • pierwszy argument: ścieżka musi mieć ukośnik końcowy (lub ukośnik odwrotny)
  • Drugi argument: domyślnie poziomie, aby NULLi będzie interpretowany jako 0o str_repeat; wyśle ​​ostrzeżenie, jeśli nie zostanie podane

function d($p,$e){$s=opendir($p);echo$b=str_repeat("\t",$e++),$e?basename($p)."/":$p,"
";while($f=readdir($s))echo preg_match("#^\.#",$f)?"":is_dir($p.$f)?d("$p$f/",$e):"$b\t$f
";}
  • wyświetla ukrytych plików i katalogów, ale nie recurse ukrytych katalogów
    dodać nawiasy wokół is_dir(...)?d(...):"..."aby usunąć ukryte dane z wyjścia (+2)
    zastąpić "#^\.#"ze #^\.+$#na wyświetlaczu / recurse ukryte wpisy ale pominąć kropka wpisy (+2)
  • może generować błędy, gdy katalogi są zagnieżdżone zbyt głęboko. Wstaw closedir($s);przed finałem }do naprawy (+13)
  • zakończy się niepowodzeniem, jeśli katalog zawiera pozycję bez nazwy, należy false!==przejść do warunku while, aby to naprawić (+8)

z glob, 182 bajty (prawdopodobnie 163 w przyszłości php)

function g($p,$e){echo$b=str_repeat("\t",$e),$e++?basename($p)."/":$p,"
";foreach(glob(preg_replace("#[*?[]#","[$1]",$p)."*",2)as$f)echo is_dir($f)?g($f,$e):"$b\t".basename($f)."
";}
  • nie wyświetla ani nie rekursuje ukrytych plików / katalogów
  • 2oznacza GLOB_MARK, doda ukośnik do wszystkich nazw katalogów, podobnie jakls -F
  • przez preg_replaceucieka GLOB znaki specjalne
    Mógłbym nadużywane preg_quotedo tego (-19); ale to się nie powiedzie w systemach Windows, ponieważ ukośnik odwrotny jest tam separatorem katalogu.
  • php może wkrótce zawierać funkcję glob_quote , która pozwoli na taką samą grę w golfa preg_quotei działanie na wszystkich systemach.

z iteratorami, 183 bajtami
(cóż, nie tylko iteratorami: używałem domyślnie SplFileInfo::__toString()do gry w golfa $f->getBaseName()i $f->isDir()starych funkcji PHP 4).

function i($p){echo"$p
";foreach($i=new RecursiveIteratorIterator(new RecursiveDirectoryIterator($p),1)as$f)echo str_repeat("\t",1+$i->getDepth()),basename($f),is_dir($f)?"/":"","
";}
  • końcowe ukośniki nie są wymagane
  • wyświetla i cyklicznie ukryte wpisy ( ls -a)
  • wstaw ,4096lub ,FilesystemIterator::SKIP_DOTSprzed, ),1aby pominąć kropki (+5) ( ls -A)
  • flaga 1oznaczaRecursiveIteratorIterator::SELF_FIRST
Tytus
źródło
0

PowerShell, 147 bajtów

param($a)function z{param($n,$d)ls $n.fullname|%{$f=$_.mode[0]-ne"d";Write-Host(" "*$d*4)"$($_.name)$(("\")[$f])";If(!$f){z $_($d+1)}}}$a;z(gi $a)1

Człowieku, wydaje mi się, że PS powinien być w stanie zrobić coś w stylu odpowiedzi na bash, ale nie wymyślam niczego krótszego niż to, co tu mam.

Wyjaśnienie:

param($a)                     # assign first passed parameter to $a
function z{param($n,$d) ... } # declare function z with $n and $d as parameters
ls $n.fullname                # list out contents of directory
|%{ ... }                     # foreach
$f=$_.namde[0]-ne"d"          # if current item is a file, $f=true
Write-Host                    # writes output to the console
(" "*$d*4)                    # multiplies a space by the depth ($d) and 4
"$($_.name)$(("\")[$f])"      # item name + the trailing slash if it is a directory
;if(!$f){z $_($d+1)}          # if it is a directory, recursively call z
$a                            # write first directory to console
z(gi $a)1                     # call z with $a as a directoryinfo object and 1 as the starting depth
ThePoShWolf
źródło
0

Python 2, 138 bajtów

Zmodyfikowano z tej odpowiedzi SO . To tabulatory wcięcia, a nie spacje. Dane wejściowe zostaną pobrane jak "C:/".

import os
p=input()
for r,d,f in os.walk(p):
    t=r.replace(p,'').count('/');print' '*t+os.path.basename(r)
    for i in f:print'   '*-~t+i

Wypróbuj online - To całkiem interesujące, że mogę przeglądać katalog w Ideone ...

Ta sama długość:

from os import*
p=input()
for r,d,f in walk(p):
    t=r.replace(p,'').count(sep);print' '*t+path.basename(r)
    for i in f:print'   '*-~t+i
mbomb007
źródło
0

Partia, 237 bajtów

@echo off
echo %~1\
for /f %%d in ('dir/s/b %1')do call:f %1 %%~ad "%%d"
exit/b
:f
set f=%~3
call set f=%%f:~1=%%
set i=
:l
set i=\t%i%
set f=%f:*\=%
if not %f%==%f:*\=% goto l
set a=%2
if %a:~0,1%==d set f=%f%\
echo %i%%f%

Gdzie \ t oznacza dosłowny znak tabulacji. Ta wersja zawiera końcowe \s na katalogach, ale 41 bajtów można zapisać, jeśli nie są potrzebne.

Neil
źródło
końcowe `s 'nie są potrzebne
tylko ASCII,
0

Perl, 89 bajtów

Jest to przydatne, gdy w podstawowej dystrybucji znajduje się moduł znajdujący. Moduł Perla :: File :: Find nie przegląda drzewa w kolejności alfabetycznej, ale specyfikacja o to nie prosiła.

/usr/bin/perl -MFile::Find -nE 'chop;find{postprocess,sub{--$d},wanted,sub{say" "x$d.$_,-d$_&&++$d&&"/"}},$_'

Właściwy skrypt ma 76 bajtów, policzyłem 13 bajtów dla opcji wiersza poleceń.

Daniel
źródło
0

Tcl , 116 bajtów

proc L f {puts [string repe \t [expr [incr ::n]-1]][file ta $f];lmap c [glob -n -d $f *] {L $c};incr ::n -1}
L $argv

Wypróbuj online!

sergiol
źródło
0

Java 8, 205 bajtów

import java.io.*;public interface M{static void p(File f,String p){System.out.println(p+f.getName());if(!f.isFile())for(File c:f.listFiles())p(c,p+"\t");}static void main(String[]a){p(new File(a[0]),"");}}

Jest to pełne przesłanie programu, które pobiera dane wejściowe z pierwszego argumentu wiersza poleceń (nie jest to wyraźnie dozwolone, ale jest wykonywane przez wiele innych) i wypisuje dane wyjściowe na standardowe wyjście.

Wypróbuj online (zwróć uwagę na inną nazwę interfejsu)

Nie golfił

import java.io.*;

public interface M {
    static void p(File f, String p) {
        System.out.println(p + f.getName());
        if (!f.isFile())
            for (File c : f.listFiles())
                p(c, p + "\t");
    }

    static void main(String[] a) {
        p(new File(a[0]), "");
    }
}
Jakob
źródło