Tôi ghét không gian trong tên tập tin


61

Nó đơn giản. Tôi không thể đứng khi mọi người sử dụng khoảng trắng khi đặt tên tệp. Nó đôi khi phá hỏng các lệnh console và làm cho đầu ra của ls trở nên xấu xí.

Thử thách là viết một chương trình (chỉ các ký tự ascii) mà

  1. đổi tên tất cả các tệp (bao gồm các thư mục) trong thư mục hiện tại thành các phiên bản có khoảng trắng bị xóa hoặc được thay thế bằng '_'
  2. khi va chạm, bạn cần nối thêm một mã định danh duy nhất (tùy thuộc vào bạn)
  3. đi xuống đệ quy vào tất cả các thư mục con

Bạn có thể giả sử tên đường dẫn kiểu UNIX. Ai sẽ cần chương trình này trên máy Windows?

Đây là mã golf, chương trình ngắn nhất giành chiến thắng (#ascii ký tự). Vì tôi ghét không gian rất nhiều, mỗi không gian phải được tính hai lần.

Vui lòng cung cấp ngôn ngữ, điểm số, chương trình của bạn và mô tả ngắn về cách chạy nó.

Chương trình phải biên dịch và thực thi với nỗ lực hợp lý trên máy linux của tôi.

EDIT: Như Etan đã yêu cầu cấu trúc tệp để thử nghiệm, đây là tập lệnh tôi hiện đang sử dụng để tạo cây tệp phù hợp:

#!/bin/bash
rm -r TestDir

touchfiles()
{
    touch my_file
    touch my__file
    touch "my file"
    touch "my  file"
    touch " my_file  "
}

mkdir TestDir
cd TestDir

touchfiles

for dir in "Test Sub" Test_Sub "Te stSub" Te_stSub
do
    mkdir "$dir"
    cd "$dir"
    touchfiles
    cd ..
done

22
Đây là cầu xin cho một giải pháp được thực hiện mà không có ký tự ascii.
Dennis Jaheruddin

50
Bây giờ tôi muốn tìm hiểu khoảng trắng
BrunoJ

10
@BrunoJ làm điều này trong Whitespace trước tiên sẽ yêu cầu bạn phát triển hệ thống truy cập tệp trong WS. Tôi nghĩ đó sẽ là thử thách nhiều hơn thử thách thực tế.
Nzall

7
Chờ đợi ai đó đăng giải pháp C / C ++ để tôi có thể đánh cắp nó, biên dịch, đăng ở dạng hex dưới dạng mã máy x86 với khoảng trắng ZERO! [hoặc có thể là cơ sở64]
Mark K Cowan

10
Tôi ghét dấu gạch dưới trong tên tập tin. Sử dụng dấu gạch ngang.
Bác sĩ Rebmu

Câu trả lời:


10

Coreshils Zsh + GNU - 48 byte (1 khoảng trắng)

for x   (**/*(Dod))mv   -T  --b=t   $x  $x:h/${${x:t}// }

Thật kỳ lạ khi bạn ghét không gian (ASCII) nhưng vẫn ổn với các tab và dòng mới, nhưng tôi đoán nó có đủ loại.

zmv giải quyết rất nhiều vấn đề đổi tên tập tin một cách chính xác (và chỉ hơi khó hiểu). Tuy nhiên, nó nhấn mạnh vào các mục tiêu là duy nhất; trong khi bạn có thể dễ dàng thêm các hậu tố duy nhất, chỉ thêm một hậu tố nếu nó cần thiết khá nhiều đòi hỏi phải thực hiện lại tất cả các công việc. Vì vậy, thay vào đó tôi lặp theo cách thủ công và dựa vào GNU mv để nối thêm một mã định danh duy nhất trong trường hợp va chạm ( --backuptùy chọn, cộng với --no-target-directorytrong trường hợp mục tiêu là một thư mục hiện có, vì nếu không mvsẽ di chuyển nguồn bên trong thư mục đó).

(od)là một vòng loại toàn cầu để sắp xếp đầu ra với các thư mục xuất hiện sau nội dung của chúng (như find -depth). Dbao gồm các tập tin dấu chấm trong toàn cầu. :h:tsửa đổi lịch sử tương tự như dirnamebasename.

mvphàn nàn rằng nó được gọi để đổi tên các tệp thành chính chúng, bởi vì toàn cầu bao gồm tên tệp không có dấu cách. C'est la vie.

Phiên bản bị đánh cắp:

for x in **/*\ *(Dod); do
  mv --no-target-directory --backup=numbered $x ${x:h}/${${x:t}// /}
done

1
Điều này không đổi tên các tập tin của tôi cả!
M.Herzkamp

@ M.Herzkamp ơi, đúng rồi, zmvbom ra trước mvcó cơ hội sắp xếp va chạm. Ok, tôi đang làm điều này bằng tay. Hóa ra là có cùng độ dài nếu tôi bỏ qua các tệp chấm và thậm chí lưu một ký tự nếu tôi không.
Gilles 'SO- ngừng trở nên xấu xa'

1
Bây giờ nó đang hoạt động. Btw: Tôi đã bao gồm hình phạt không gian tại thời điểm mà tôi thực sự có ác cảm với không gian;) Trớ trêu thay, tôi đã không loại trừ khoảng trống khi tôi đăng thử thách: P
M.Herzkamp

13

Bash 116 byte, 16 khoảng trắng

find . -depth -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// /_}"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;

Tôi đã không loại bỏ lỗi để có thêm một vài byte. Điều này sẽ không có bất kỳ va chạm.

Nếu GNU không phải là posix findcó thể được mong đợi, điều này có thể được rút ngắn hơn nữa:

Bash 110 byte, 15 khoảng trắng

find -d -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// /_}"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;

Xóa khoảng trắng thay vì thay thế chúng sử dụng hai byte ít hơn:

Bash 108 byte, 15 khoảng trắng

find -d -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// }"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;

Lưu ý: nếu các tab có thể được sử dụng thay cho khoảng trắng, chỉ cần 1 khoảng trắng (một trong quy tắc khớp để thay thế ở dòng 2).

Cảm ơn Dennis vì đã tìm ra lỗi trên trích dẫn kép (và cung cấp giải pháp)


11
LÀ KHÔNG GIAN TUYỆT VỜI TÌM HIỂU ĐỂ KIẾM ĐƯỢC TÔI ??? ;-)
M.Herzkamp

@ M.Herzkamp Tôi mặc dù đó là một lỗi sao chép và dán, nhưng nó thực sự ở đó. Đoán tôi đạt được thêm 2 điểm. Ngoài ra, -depthtrong GNU có thể được thay thế bởi -d, mặc dù nó phàn nàn rằng nó không được dùng nữa. Tôi không biết về luật chơi golf, tôi có thể làm điều đó không?
pqnet

2
Miễn là nó hoạt động, tôi cho phép nó. Nếu sự phản đối trở thành loại bỏ trong một phiên bản trong tương lai, tôi có thể phải quay lại câu trả lời này và từ chối vì nó không chính xác ;-)
M.Herzkamp

2
Điều này sẽ không hoạt động đúng nếu bất kỳ tên tệp nào có trích dẫn kép. Để khắc phục điều này, bạn có thể sử dụng bash -c 'B=${0##*/}...' {} \;thay thế, nó thực sự ngắn hơn.
Dennis

3
Tôi đoán tôi sẽ là người đó, có chuyện gì với Nbiến? Nó không bao giờ được định nghĩa ...
Steven Penny

9

Python 180 byte

from    os  import*
t,c,h='.',chdir,path
def g(p):
    c(p)
    for x   in  listdir(t):
        if h.isdir(x):g(x)
        n=x.replace(' ','')
        while h.exists(n):n+=t
        if' 'in x:rename(x,n)
    c(t*2)
g(t)

chỉ có 2 khoảng trắng nếu bạn sử dụng tab để thụt lề :-)


Tôi đoán hầu hết các câu trả lời khác có thể cải thiện điểm số của họ bằng cách sử dụng các tab thay vì khoảng trắng.
kasperd

Nhưng trình của bạn sử dụng không gian không? (+1 cho mã làm việc)
M.Herzkamp

Tôi không biết làm thế nào để nhận được các ký tự tab trong câu trả lời ...
Emanuele Paolini

2
được thay thế bằng các tab :-)
Emanuele Paolini

3
Thật xấu xí ... Chà, tôi đoán là tôi đã yêu cầu nó :(
M.Herzkamp

5

Nếu thứ tự các hậu tố tệp bị va chạm không cần phải tạo tiền lệ cho tệp tồn tại trước đó thì các công việc sau đây đối với tôi:

bash / find / mv 84 byte, 16 dấu cách

find -depth -execdir bash -c '[ "${0//[^ ]}" ] && mv -{T,--b=t} "$0" "${0// }"' {} \;

bash / find / mv 82 byte, 14 khoảng trắng

find -depth -execdir bash -c '[ "${0//[^ ]}" ]&&mv -{T,-b=t} "$0" "${0// }"' {} \;

Ôm ấp &&để lưu hai byte không gian.

bash / find / mv 60 byte, 11 dấu cách

find -d -execdir bash -c 'mv -{T,-b=t} "$0" "${0// }"' {} \;

Giảm bảo vệ lỗi để nó nhận được lỗi từ mv trên các tệp không có khoảng trắng để bắt đầu.

Chỉnh sửa: Bỏ các trích dẫn từ {}như được nhắc nhở bởi Dennis. Cũng được phép findhét lên về tính di động và sự phản đối trong phiên bản ngắn nhất, nơi mvđã hét lên về việc di chuyển một tệp trên đầu trang của chính nó.

Chỉnh sửa 2: Thêm -Tđể mvchỉ huy để tránh thư mục làm tổ thay vì đổi tên như chỉ ra bởi pqnet. Sử dụng mở rộng cú đúp với chi phí của một ký tự chỉ bằng cách sử dụng một khoảng trắng.


Bạn có thể sử dụng -dthay vì -depthvà bạn không cần các trích dẫn xung quanh {}.
Dennis

@Dennis Vâng. Tôi đã thấy -dcuộc trò chuyện trên câu trả lời của pqnet nhưng hình dung từ khi tôi im lặng thì mvtôi sẽ tránh được findtiếng la hét. Mặc dù tôi có lẽ nên rút ngắn nó cho người đang la hét. Và vâng, tôi luôn trích dẫn {}vì một số lý do mặc dù tôi biết bạn không phải làm thế trong trường hợp này. Tôi đoán là có thói quen.
Etan Reisner

1
Khi xung đột xảy ra trên tên thư mục, nó sẽ đặt cái này vào cái khác (và không phải dải không gian). Sử dụng -Ttùy chọn để mvtránh điều này
pqnet

Điều này hoạt động, và tôi đã nói trong thử thách rằng phụ lục là tùy thuộc vào bạn. +1
M.Herzkamp

4

NodeJS - 209 byte, 3 khoảng trắng

s=require('fs');function a(d){s.readdirSync(d).forEach(function(f){f=d+'/'+f;i=0;r=f;if(/ /.test(f)){r=f.replace(' ','');while(s.existsSync(r))r+=i++;s.renameSync(f,r)}s.statSync(r).isDirectory()&&a(r)})}a('.');

Tôi không quen thuộc với node.js. Làm thế nào tôi có thể chạy nó?
M.Herzkamp

Bạn sẽ cần các nútj thực thi Node ; lưu nó trong một tập tin và chạynode file.js
cPu1

7
Tôi nhận được một ngoại lệ TypeError: Object #<Object> has no method 'exists'. Đoán xem: nó ở dòng 1! : D
M.Herzkamp

Tôi đã thử nó. Dù sao, tôi đã thay thế tồn tại với đối tác đồng bộ của nó. Bạn có thể thử ngay bây giờ?
cPu1

1
Tôi chỉ cài đặt phiên bản 0.6.12. Đó có lẽ là vấn đề.
M.Herzkamp

2

Bash - 86 byte

find    .   -d|while    IFS=""  read    f;do    t=${f##*/};mv   --b=t   -T  "$f"    "${f%/*}"/${t// /};done

Rất tiếc, sẽ có một cái nhìn
Subbeh

2
Ngoài ra, không gian được tính hai lần ;-)
M.Herzkamp

chính xác những gì bạn có nghĩa là với không gian được tính hai lần?
Subbeh

1
Bạn có thể lưu rất nhiều ký tự bằng cách viết tắt --backupthành--b

1
Vâng, bây giờ nó hoạt động với bộ thử nghiệm của tôi là tốt! +1
M.Herzkamp

2

Bash + Perl rename64

( renamelà tập lệnh Perl trên Debian và các dẫn xuất, không phải lệnh produc-linux.)

find . -depth -name "* *" -execdir rename 'y/ /_/' * \;

11
Điều gì xảy ra nếu "my file.txt" và "my_file.txt" đều có mặt?
M.Herzkamp

1
Ồ đúng rồi .. Làm việc sớm thôi
German_guy

1
*nên {}, vì nó đứng này chỉ đổi tên các tập tin có tên xuất hiện trong thư mục hiện tại. Điều này không nối thêm hậu tố trong trường hợp va chạm. Bạn có thể tiết kiệm khá nhiều bằng cách bỏ qua -name "* *"renameâm thầm bỏ qua các tệp có tên không được chuyển đổi.
Gilles 'SO- ngừng trở nên xấu xa'

2

POSIX sh+ GNU find+ GNU mv67 ASCII byte + một khoảng trống (bằng chữ)

find    -d  -exec   sh  -cf 'IFS=\ ;IFS=_   set $0;mv   --b=t   "$0"    "$*"'   {}  \;

Tôi không biết nó có phù hợp không, nhưng với điều này, bất kỳ chuỗi không gian nào cũng được tách ra thành một _- dù sao tôi cũng thích nó. Trên thực tế, bất kỳ chuỗi nào nhưng không gian dẫn đầu / dấu đó là - những khoảng đó được tự động cắt ngắn (đó cũng là, tôi nghĩ, đó là một hành vi có lợi) . Cảm ơn Gilles đã chỉ ra điều này.

Điều này chỉ sử dụng dấu tách trường nội bộ để tách các trường.

Nó khá ... trò chuyện ...

...trời ơi. Tôi biết điều tab là rẻ, nhưng tôi nghĩ rằng nó ít nhất là thông minh. Bây giờ tôi chỉ đến bữa tiệc muộn ...


Điều này hoạt động trên thử nghiệm của tôi như bạn dự định, nhưng không phải là thách thức yêu cầu. Tôi thích nó, mặc dù, bởi vì tôi có thể sẽ học được một cái gì đó mới. Tôi đoán tôi sẽ phải đọc về điều IFSkỳ diệu này ...
M.Herzkamp

1
@ M.Herzkamp - ifs hoạt động khác nhau tùy thuộc vào việc nó có được đặt thành khoảng trắng hay không. Hầu hết mọi người ghét nó bởi vì họ không hiểu hai phẩm chất chính của nó - rằng nó chỉ hoạt động trên các bản mở rộng ( $expandkhông phải (ex pand)) và điều ifsws vừa đề cập. Nhìn vào đây
mikeerv

Điều này không đổi tên các tập tin trong các thư mục có tên chứa khoảng trắng. Một sửa chữa sẽ được thay thế -execbằng -execdir. Điều khó hiểu hơn IFSmà bạn không đề cập đến là các dấu cách bị xóa. Lưu ý rằng như những người khác đã nhận thấy bạn cũng cần -Ttùy chọn này mv, khi mục tiêu của mvcuộc gọi là một thư mục hiện có.
Gilles 'SO- ngừng trở nên xấu xa'

@Gilles - sở thích của tôi sẽ là sử dụng sh -c 'mkdir -p ../newtree/"$0"; ln "$0"/* ../newtree/$0 {} \;và các câu hỏi khác trong một find -type dlệnh để tạo ra một cây liên kết cứng được nhân đôi và sau đó hoạt động trên những cái đó, nhưng tôi đoán là đang viết một cú đánh golf mã cho một hoạt động di chuyển. Điểm hay về các không gian hàng đầu / dấu, mặc dù tôi nghĩ đó cũng là một hành vi tôi muốn.
mikeerv

@Gilles - nhưng bằng cách này, nó không phải là một điều không minh bạch - đó là một dự định và tiêu chuẩn kiểm soát hành vi. Phần Chia tách trường nằm trong số rất ít trong thông số kỹ thuật không chứa các từ không xác định hoặc xác định do triển khai . Không có bảo đảm như vậy với zsh's chức năng được xây dựng trong zmv ví dụ.
mikeerv

2

PHP, 147 145 byte, 2 1 không gian s -> 146

function    s(){foreach(glob("*")as$n){is_dir($n)&&chdir($n)&s()|chdir("..");if($n<$r=strtr($n," ",_)){while(file_exists($r))$r.=_;rename($n,$r);}}}

Hàm đệ quy. Chạy vớis(".");

Lặp lại globkết quả cho đường dẫn đã cho:

  • nếu thư mục, tái diễn
  • thay thế dấu cách bằng dấu gạch dưới
  • nếu chuỗi khác nhau
    • trong khi tên tệp mới được lấy, nối thêm dấu gạch dưới
    • đổi tên tập tin / thư mục

php sẽ đổi tên các tệp trên máy chủ ... Bây giờ tôi tự hỏi làm thế nào để thay đổi tên tệp của khách hàng bất cứ khi nào họ truy cập trang web của bạn: D
M.Herzkamp 6/2/2017

1

Ruby 121

require 'find'

Find.find('.') do |file|
  if file.chomp.match(/ /)
    File.rename(file, file.gsub(/ /, '_'))
  end
end

6
Chào mừng bạn đến với Code Golf! Ý tưởng ở đây trong những thử thách chơi gôn mã này là sử dụng số lượng nhân vật ít nhất. Điều đó có nghĩa rằng bạn chắc chắn có thể thoát khỏi dòng trống và các tab, và làm cho tên biến đơn nhân vật, nhưng người tìm kiếm tất cả các loại của những cách sáng tạo để giảm số lượng nhân vật.
Không phải Charles

Tôi gặp một lỗi, rằng Thư mục không trống:gam3.rb:5:in `rename': Directory not empty - ./Te stSub or ./Te_stSub (Errno::ENOTEMPTY) from gam3.rb:5 from /usr/lib/ruby/1.8/find.rb:39:in `find' from /usr/lib/ruby/1.8/find.rb:38:in `catch' from /usr/lib/ruby/1.8/find.rb:38:in `find' from gam3.rb:3
M.Herzkamp

1

Con trăn, 187

165, cộng với 22 điểm phạt cho các khoảng trống.

from os import*
u='_';j=path.join
for t,d,f in walk('.',0):
 for z in f+d:
  n=z.replace(' ',u)
  if n!=z:
   while path.exists(j(t,n)):n+=u
   rename(j(t,z),j(t,n))

166, sử dụng thủ thuật của Emanuele :

Chỉ có một không gian duy nhất trong cái này!

from    os  import*
u='_';j=path.join
for t,d,f   in  walk('.',0):
    for z   in  f+d:
        n=z.replace(' ',u)
        if  n!=z:
            while   path.exists(j(t,n)):n+=u
            rename(j(t,z),j(t,n))

Điều này làm việc cho tôi. +1
M.Herzkamp

xóa các khoảng trắng ở đầu các dòng và sử dụng các tab - chúng không có khoảng trắng nên chỉ được tính một lần
chill0r

@ chill0r Đó là phiên bản thứ hai; tất cả các khoảng trắng được thay thế bằng các tab trừ một (trừ SO vẫn hiển thị chúng dưới dạng khoảng trắng).
Henry Keiter


0

Bash 4+ 111 byte

shopt -s dotglob globstar
for f in **
do
n=${f// /}
while [[ $f != $n && -e $n ]]
do n+=1
done
mv "$f" $n
done

1
Vấn đề tương tự như một số mục khác: Bạn thay thế khoảng trắng trong thư mục mẹ và mv không thể tìm thấy chúng. Ngoài ra, bạn phải thay đổi hướng di chuyển, nếu không bạn đổi tên thư mục và mv không thể tìm thấy các tệp bên trong.
M.Herzkamp

0

Groovy, 139 ký tự

def c
c={
f->
def g=new File(f.parent,f.name.replaceAll('\\s',''))
f.renameTo(g)
!g.directory ?: g.eachFile(c)
}
new File('.').eachFile(c)

theo bình luận @ edc65

Groovy, xử lý va chạm, 259 ký tự

def c
c={
p,l,f->
def g=new File(p,f.name.replaceAll('\\s',''))
f==g?:
(g.exists()?f.renameTo(g.toString()+l.indexOf(f.name)):f.renameTo(g))
!g.directory?:g.eachFile(c.curry(g,g.list().toList()))
}
def r=new File('.')
r.eachFile(c.curry(r,r.list().toList()))

1
Điều này không xử lý va chạm.
edc65

Đảm bảo rằng các tệp được đổi tên trước các thư mục mẹ của chúng và các khoảng trắng trong thư mục mẹ không bị thay thế.
M.Herzkamp

Tôi chắc chắn là ổn
đăng nhập vào

0

POSIX (Đã thử nghiệm trên zsh) + các lệnh Linux cơ bản 151

export IFS='
'
for f in $(ls -R1);do export n=$(echo $f|tr ' ' '_');yes n|mv $f $n || yes n|mv $f `echo $n;echo $f|md5sum`
done

@ M.Herzkamp Đã sửa.
LinGeek

Một số điều: chức năng xuất IFS và c trong ls -cR là gì? Và phiên bản nào của mv bạn cần cho tùy chọn --reply? (Tôi có 8.13 và nó không nhận ra tùy chọn này). Ngoài ra để có được điểm cao hơn, bạn nên viết tắt tên biến của mình.
M.Herzkamp

Các c thay thế không gian với dòng mới. IFS dừng không gian là dải phân cách. --Reply là từ các phiên bản cũ và sắp sửa.
LinGeek

1
Bạn đang thiếu một mv thứ hai trong dòng 5? Và tôi nghĩ rằng một tiếng vang trong dòng đó là sai.
M.Herzkamp

1
$(ls -CR)là hoàn toàn không có thật. Các -ctùy chọn là vô ích, và -Rgiúp bạn tập tin mà không thư mục của họ, đó là vô nghĩa. Kiến trúc của bạn về cơ bản sẽ không xử lý tên tệp có chứa dòng mới. Bạn cần set -fhoặc tên tập tin khác chứa ký tự đại diện sẽ phát nổ. exportlà vô dụng Tôi có thể mơ hồ nhìn thấy những gì bạn đang cố gắng làm để xác định các tập tin, nhưng đường ống là sai.
Gilles 'SO- ngừng trở nên xấu xa'
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.