Viết chương trình hiển thị thư mục cây


9

Đưa ra một thư mục (chẳng hạn như C:/), được đưa ra từ stdin hoặc đọc từ một tệp, tạo ra một cây thư mục, với mỗi tệp / thư mục được thụt vào dựa trên độ sâu của nó.

Thí dụ

Nếu tôi có một C:/ổ đĩa mà chỉ chứa hai thư mục foobar, và barlà sản phẩm nào trong khi foochứa baz.txt, sau đó chạy với đầu vào C:/sản xuất:

C:/
    bar/
    foo/
        baz.txt

Trong khi chạy với đầu vào C:/foo/sẽ tạo ra

foo/
    baz.txt

Vì đây là codegolf, số byte thấp nhất sẽ thắng. Các phần mở rộng tập tin (như baz.txt) là tùy chọn. Ghi chú thêm: các tệp ẩn có thể bị bỏ qua, các thư mục phải thực sự tồn tại, có thể giả định rằng các tệp không chứa các ký tự không thể in hoặc các dòng mới nhưng tất cả các ký tự ASCII có thể in khác đều ổn (tên tệp có khoảng trắng phải được hỗ trợ). Đầu ra có thể được ghi vào tập tin hoặc thiết bị xuất chuẩn. Các vết lõm có thể được tạo thành từ một ký tự tab hoặc 4 khoảng trắng.


1
Lưu ý thêm: câu hỏi này được định dạng kém, vì vậy một định dạng lại sẽ được đánh giá cao.
Toán học

Các ngôn ngữ không có quyền truy cập vào các tệp tự động bị loại?
Leaky Nun

Tên tập tin nào phải được hỗ trợ? Tập tin có khoảng trắng trong tên của họ? Với dòng mới? Với các ký tự không thể in? Điều gì về các tập tin ẩn (bắt đầu với .)?
Doorknob

1
@LeakyNun Đầu ra của câu hỏi tham chiếu là một mảng các mảng. Câu hỏi này yêu cầu một đại diện của cây thư mục được in ra thiết bị xuất chuẩn.
Toán học

1
Đầu vào có thể là một tham số chuỗi cho một chức năng?
mbomb007

Câu trả lời:


10

bash, 61 58 54 byte

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

Lấy đầu vào làm đối số dòng lệnh, đầu ra trên STDOUT.

Lưu ý rằng các khoảng trắng ở gần cuối trước khi |gthực sự là một ký tự tab (SE chuyển đổi chúng thành khoảng trắng khi hiển thị các bài đăng).

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
'

Cảm ơn @Dennis cho 4 byte!


2

APL Dyalog , 48 byte

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

nhắc nhở nhập ký tự

'dir/s/b ', viết lại văn bản

⎕SH thực hiện trong shell

r←lưu trữ trong r

lập danh sách các chuỗi thành ma trận ký tự

chỉ số phân loại tăng dần

r[... ]Sắp xếp lại r [sắp xếp]

(... )trên tiêu chuẩn ngoài lệnh shell, hãy làm:

'[^\\]+\\'⎕R' ' regex thay thế các dấu gạch chéo không kết thúc bằng dấu gạch chéo bằng bốn dấu cách

1↓ thả dòng đầu tiên

⊂∘⊃, đặt trước [dòng] kèm theo

Kết quả nhập "\ tmp" vào lời nhắc bắt đầu như sau trên máy tính của tôi:

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


Không phải các thư mục được cho là có dấu \ ký tự?
Neil


2

SML , 176 byte

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)

Khai báo (trong số các hàm khác) một hàm %lấy một chuỗi làm đối số. Gọi với % "C:/Some/Path";hoặc % (getDir());cho thư mục hiện tại.

Tôi đang sử dụng ngôn ngữ StandardML thường được sử dụng theo chức năng mà có FileSysThư viện tôi đã khám phá sau khi đọc thử thách này.

Các ký tự đặc biệt !, &, $%không có ý nghĩa đặc biệt trong ngôn ngữ riêng của mình và chỉ đơn giản là sử dụng như định danh; tuy nhiên chúng không thể được trộn lẫn với các định danh chữ và số tiêu chuẩn cho phép loại bỏ khá nhiều khoảng trắng cần thiết.

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 &
)

Có thể được biên dịch như thế này với SML / NJ hoặc với Moscow ML * bằng cách thêm tiền tố vào load"OS";.

* Xem mosml.org, không thể đăng nhiều hơn 2 liên kết.


1

C # (.NET Core) , 222 byte

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

Hãy thử trực tuyến!


Con linh cẩu:

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

Lần đầu tiên tôi từng đệ quy một Mainhàm!

Tôi tin rằng một người có kiến ​​thức mới hơn về C # có thể chơi golf nhiều hơn, vì tôi đã không lập trình trên C # một thời gian!


0

PHP, 180 byte

  • đối số đầu tiên: đường dẫn phải có dấu gạch chéo (hoặc dấu gạch chéo ngược)
  • đối số thứ hai: mức mặc định đến NULLvà sẽ được hiểu là 0bởi str_repeat; sẽ đưa ra cảnh báo nếu không được cung cấp

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
";}
  • hiển thị các tập tin ẩn và thư mục, nhưng không recurse thư mục ẩn
    thêm ngoặc xung quanh is_dir(...)?d(...):"..."để loại bỏ các mục ẩn từ đầu ra (2)
    thay thế "#^\.#"với #^\.+$#màn hình hiển thị / recurse mục ẩn nhưng skip dot mục (+2)
  • có thể ném lỗi khi các thư mục được lồng quá sâu. Chèn closedir($s);trước trận chung kết }để sửa (+13)
  • sẽ thất bại nếu một thư mục chứa mục không có tên, hãy thêm vào false!==điều kiện while để sửa (+8)

với toàn cầu, 182 byte (có thể là 163 trong php tương lai)

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)."
";}
  • không hiển thị hoặc lặp lại các tập tin / thư mục ẩn
  • 2là viết tắt của GLOB_MARK, sẽ thêm một dấu gạch chéo vào tất cả các tên thư mục, cũng nhưls -F
  • các preg_replacenhân vật đặc biệt thoát khỏi thế giới
    mà tôi có thể đã lạm dụng preg_quotecho việc này (-19); nhưng điều đó sẽ thất bại trên các hệ thống Windows, vì dấu gạch chéo ngược là dấu phân cách thư mục ở đó.
  • php có thể sớm bao gồm một hàm global_quote , sẽ cho phép chơi golf giống như preg_quotevà hoạt động trên tất cả các hệ thống.

với các trình vòng lặp, 183 byte
(tốt, không hoàn toàn là các trình vòng lặp: Tôi đã sử dụng ngầm SplFileInfo::__toString()cho golf $f->getBaseName()$f->isDir()các hàm PHP 4 cũ.)

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)?"/":"","
";}
  • không cần dấu gạch chéo
  • hiển thị và đệ quy các mục ẩn ( ls -a)
  • chèn ,4096hoặc ,FilesystemIterator::SKIP_DOTStrước ),1để bỏ qua các mục chấm (+5) ( ls -A)
  • cờ 1là viết tắt củaRecursiveIteratorIterator::SELF_FIRST

0

PowerShell, 147 byte

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

Man, tôi cảm thấy như PS sẽ có thể làm một cái gì đó giống như câu trả lời bash, nhưng tôi không nghĩ ra bất cứ điều gì ngắn hơn những gì tôi đã có ở đây.

Giải trình:

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

0

Python 2, 138 byte

Sửa đổi từ câu trả lời SO này . Đó là các tab để thụt lề, không phải khoảng trắng. Đầu vào sẽ được thực hiện như thế nào "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

Dùng thử trực tuyến - Thật thú vị khi tôi được phép duyệt thư mục trên Ideone ...

Cùng chiều dài:

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

0

Mẻ, 237 byte

@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%

Trong đó \ t đại diện cho ký tự tab theo nghĩa đen. Phiên bản này bao gồm các dấu \trên các thư mục nhưng có thể lưu 41 byte nếu không cần thiết.


dấu vết không cần thiết
ASCII

0

Perl, 89 byte

Nó hữu ích khi có một mô-đun tìm trong phân phối cốt lõi. Perl's File :: Tìm mô-đun không đi qua cây theo thứ tự chữ cái, nhưng thông số kỹ thuật không yêu cầu điều đó.

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

Kịch bản phù hợp là 76 byte, tôi đếm 13 byte cho các tùy chọn dòng lệnh.



0

Java 8, 205 byte

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]),"");}}

Đây là một đệ trình chương trình đầy đủ lấy đầu vào từ đối số dòng lệnh đầu tiên của nó (không được phép rõ ràng, nhưng được thực hiện bởi nhiều người khác) và in đầu ra thành tiêu chuẩn.

Dùng thử trực tuyến (lưu ý tên giao diện khác nhau)

Ung dung

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]), "");
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.