Dosya adlarındaki boşluklardan nefret ediyorum


61

Basit. Dosya adlandırmada insanlar boşluk kullandığında dayanamıyorum. Bazen konsol komutlarını mahveder ve ls çıktısını çirkin yapar.

Buradaki zorluk bir program yazmaktır (sadece ascii karakterler).

  1. Geçerli dizindeki tüm dosyaları (dizinler dahil), '_' ile kaldırılmış veya değiştirilmiş boşluklarla değiştirir
  2. Çarpışmada, benzersiz bir tanımlayıcı eklemeniz gerekir (size kalmış)
  3. yinelenerek tüm alt dizinlere iner

UNIX tarzı yol adlarını kabul edebilirsiniz. Zaten bir Windows makinesinde bu programa kim ihtiyaç duyacak?

Bu kod golf, en kısa program kazanıyor (#ascii karakterleri). Uzaylardan çok nefret ettiğimden, her alanın iki kez sayılması gerekir.

Lütfen dilinizi, puanınızı, programınızı ve nasıl çalıştırılacağınızla ilgili kısa bir açıklama girin.

Program, Linux makinemde makul bir çaba ile derlenmeli ve yürütülmelidir.

EDIT: Etan test için bir dosya yapısı istediğinden, şu anda uygun bir dosya ağacı oluşturmak için kullandığım komut dosyası:

#!/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
Bu ascii karakterleri olmadan yapılan bir çözüm için yalvarıyor.
Dennis Jaheruddin

50
Şimdi Boşlukları öğrenmek istiyorum
BrunoJ

10
@BrunoJ bunu Whitespace'de yapmak için öncelikle WS'de bir dosya erişim sistemi geliştirmenizi gerektirecektir. Bunun asıl mücadeleden daha zor olacağını düşünüyorum.
Nzall

7
Birisinin bir C / C ++ çözümü göndermesini bekliyorum, böylece onu çalabilirim, derleyeyim, hex ile SIFIR boşluklarla x86 makine kodu olarak gönderebilirim! [veya belki base64]
Mark K Cowan

10
Dosya adlarındaki alt çizgilerden nefret ediyorum. Tire kullanın.
Dr. Rebmu

Yanıtlar:


10

Zsh + GNU coreutils - 48 bayt (1 boşluk)

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

(ASCII) boşluklarından nefret etmen garip ama sekmeler ve yeni satırlarla iyi, ama sanırım her türlü sürüyor.

zmv , çok sayıda dosya yeniden adlandırma sorununu tam olarak (ve sadece biraz gizlice) çözer . Ancak, hedeflerin benzersiz olması konusunda ısrar ediyor; Kolayca benzersiz son ekler ekleyebilseniz de, yalnızca hemen gerekmesi durumunda bir son ek eklemek tüm işi yeniden yapmayı gerektirir. Bu yüzden , çarpışma durumunda benzersiz bir tanımlayıcı eklemek için manuel olarak döngüdeyim ve GNU mv'ye güveniyorum ( --backupseçenek, ayrıca --no-target-directoryhedefin varolan bir dizin olması durumunda mv, kaynağı o dizinin içinde taşıyacağı gibi ).

(od)Çıktıyı içeriklerinden sonra görünen dizinlerle sıralamak için bir glob niteleyicisidir-depth . Dglobdaki nokta dosyalarını içerir. :hve :tolan tarih düzenleyiciler benzer dirnameve basename.

mvglob, boşluk içermeyen dosya adları içerdiğinden, dosyaların kendilerinin adını değiştirmeye çağrıldığından şikayet eder. C'est la vie.

Ungolfed versiyonu:

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

1
bu benim dosyalarımı yeniden adlandırmaz!
M.Herzkamp

@ M.Herzkamp Oh, doğru, daha zmvönce dışarı çıkan bombalar , mvçarpışmaları çözme şansı buldu. Tamam, bunu elle yapıyorum. Nokta dosyalarını atlarsam tam olarak aynı uzunlukta olur ve eğer yapmazsam bir karakter bile kaydeder.
Gilles 'SO- kötülük yapmayı bırak'

1
Şimdi çalışıyor. Btw: Gerçekten boşluklara karşı
kinimi çektiğim

13

Bash 116 bayt, 16 boşluk

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

Birkaç bayt daha kazanmak için hataları bastırmadım. Bunun herhangi bir çarpışması olmayacak.

Posix olmayan GNU findbeklenebilirse, bu daha da kısaltılabilir:

Bash 110 bayt, 15 boşluk

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

Bunları değiştirmek yerine boşlukları kaldırmak, iki daha az bayt kullanır:

Bash 108 bayt, 15 boşluk

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

Not: boşluklar yerine sekmeler kullanılabiliyorsa, sadece 1 boşluk gerekir (satır 2'de yer değiştirme için eşleşme kuralında olan).

Çifte alıntıda hata bulduğu için Dennis'e teşekkür ederim (ve çözüm sağlar)


11
EKSTRA UZAY, MOCK ME BUNU NEDİR? ;-)
M.Herzkamp

@ M.Herzkamp Bir kopyalayıp yapıştırma hatası olmasına rağmen, aslında orada. Sanırım 2 puan daha kazandım. Ayrıca, -depthGNU’da yerinden edilmesine -drağmen şikâyet edildiğinden şikayetçi. Golf kurallarını bilmiyorum, bunu yapabilir miyim?
pqnet

2
Çalıştığı sürece izin veriyorum. İtirazın gelecekteki bir sürümde kaldırılması durumunda, bu cevaba geri dönüp doğru olmadığım için
aşağı indirmem gerekebilir

2
Dosya adlarından herhangi biri çift tırnak işareti içeriyorsa bu düzgün çalışmaz. Bunu düzeltmek için, bash -c 'B=${0##*/}...' {} \;yerine daha kısa olanı kullanabilirsiniz .
Dennis,

3
Galiba o adam olacağım, Ndeğişkene ne oldu ? Asla tanımlanmadı ...
Steven Penny

9

Python 180 bayt

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)

girinti için sekme kullanırsanız sadece 2 boşluk :-)


Sanırım diğer cevapların çoğu da boşluklar yerine sekmeler kullanarak puanlarını artırabilir.
kasperd

Ama gönderiminde boşluk kullanılıyor, değil mi? (Çalışma kodu için +1)
M.Herzkamp

Cevaptaki sekme karakterlerine nasıl bakacağımı bilmiyorum ...
Emanuele Paolini

2
sekmelerle değiştirildi :-)
Emanuele Paolini

3
Ne kadar çirkin ... Şey, sanırım bunun için sordum :(
M.Herzkamp

5

Çarpıştırılmış dosya soneklerinin sırasının önceden var olan dosyaya emsal vermek zorunda kalmaması durumunda, aşağıdakiler benim için çalışır:

bash / find / mv 84 bayt, 16 boşluk

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

bash / find / mv 82 bayt, 14 boşluk

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

&&İki boşluk baytını kurtarmak için sarıldı .

bash / find / mv 60 bayt, 11 boşluk

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

Hata korumasını azaltır, böylece başlangıçta boşluğu olmayan dosyalarda mv'den hata alır.

Düzenleme: {}Dennis'in hatırlattığı şekilde alıntıları düşürdüm. Ayrıca , bir dosyayı kendi üzerine taşımak findüzere çığlık atmakta olan en kısa sürümde taşınabilirlik ve kullanımdan kaldırma hakkında çığlık atmasına izin verildi mv.

Düzenleme 2: pqnet tarafından belirtildiği şekilde yeniden adlandırmak yerine iç içe geçmiş dizinleri önlemek -Tiçin mvkomuta eklendi. Sadece bir boşluk kullanarak bir karakterin maliyeti pahasına kullanılan payanda.


Sen kullanabilirsiniz -dyerine -depthve çevresine tırnak içine alınması gerekmez {}.
Dennis

@Dennis Evet. -dPqnet'in cevabındaki sohbeti gördüm ama mvçığlığı susturduğumdan beri çığlıktan kaçınacağımı düşündüm find. Yine de çığlık atan kişi için onu kısaltmalıyım. Ve evet, bu durumda olmanız gerekmediğini bilmeme{} rağmen her zaman bir nedenle teklif ediyorum . Alışkanlığın gücü sanırım.
Etan Reisner

1
Dizin isimlerinde çarpışma gerçekleştiğinde, birbiri içine geçecek (boşluk bırakmayacak). Bundan kaçınmak -Tiçin seçeneği kullanınmv
pqnet

Bu işe yarıyor ve zorlukla ekin size kalmış olduğunu söyledim. +1
M.Herzkamp

4

DüğümJS - 209 bayt, 3 Boşluk

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('.');

Node.js.'ye aşina değilim Nasıl çalıştırırım?
M.Herzkamp

Düğümün çalıştırılabilir düğümlerine ihtiyacınız olacak ; bir dosyaya kaydedin ve çalıştırınnode file.js
cPu1

7
Bir istisna alıyorum TypeError: Object #<Object> has no method 'exists'. Tahmin et nerede: 1. sırada! : D
M.Herzkamp

Test ettim. Her neyse, yerini değiştirilen eş karşılığı var. Şimdi deneyebilir misin?
cPu1

1
Yüklü sadece 0.6.12 sürümüm var. Sorun bu olabilir.
M.Herzkamp

2

Bash - 86 bayt

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

Oops, bir göz
atacak

2
Ayrıca, boşluklar iki kez sayılır ;-)
M.Herzkamp

boşluklarla tam olarak ne demek iki kere sayılır?
Subbeh

1
Kısaltma --backupyaparak birçok karakteri kaydedebilirsiniz--b

1
Evet, şimdi test setimle de çalışıyor! +1
M.Herzkamp

2

Bash + Perl rename64

( renameutil-linux komutu yerine Debian ve türevlerinde Perl betiğidir.)

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

11
"My file.txt" ve "my_file.txt" ikisi de mevcutsa ne olur?
M.Herzkamp

1
Ah doğru .. Yakında bunun üzerinde çalışıyor
german_guy

1
*olması gerektiği gibi {}, bu sadece ismini geçerli dizinde görünen dosyaları yeniden adlandırır. Bu çarpışma durumunda bir son ekini eklemez. Sessizce biraz tasarruf yapabilirsiniz -name "* *"çünkü renameadı sessizce dönüştürülmeyen dosyaları yoksayar.
Gilles 'SO- kötülük' dur

2

POSIX sh+ GNU find+ GNU mv67 ASCII bayt + bir (değişmez) alanı

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

Uyuyor mu bilmiyorum, ama bununla herhangi bir boşluk dizisi teke seçildi _- yine de hoşuma gitti. Aslına bakarsanız, herhangi bir sekanstan başka olan / takip eden boşluklar - bunlar otomatik olarak kesiliyor (ki, sanırım, yararlı bir davranış) . Bu işaret için Gilles teşekkür ederiz.

Bu sadece alanları ayırmak için iç alan ayırıcısını kullanır.

Oldukça ... konuşkan ...

... ahbap. Sekme işinin ucuz olduğunu biliyordum, ama en azından zekice olduğunu düşündüm. Şimdi partiye geç kaldım ...


Bu, test kümemde istediğiniz şekilde çalışır, ancak zorlukların gerektirdiği gibi olmaz. Yine de hoşuma gidiyor, çünkü muhtemelen yeni bir şeyler öğreneceğim. Sanırım bu IFSsihirli şeyi okumak zorunda kalacağım ...
M.Herzkamp

1
@ M.Herzkamp - Beyaz boşluk olarak ayarlanıp ayarlanmadığına bağlı olarak farklı davranırsa. Çoğu insan ondan nefret eder çünkü iki temel özelliğini anlamamaktadır - yalnızca genişlemelerde (eski ( $expanddeğil)) ve sadece bahsetmiş olan ifsws olayında çalışmaktadır. Buraya
mikeserv

Bu, adları boşluk içeren dizinlerin içindeki dosyaları yeniden adlandırmaz. Bir düzeltme değiştirmek şeklinde olur -execile -execdir. “Bahsetmediğiniz bir tuhaflık IFS, takip eden boşlukların silinmesidir. Diğerlerinin fark -Tettiği mvgibi, bir mvaramanın hedefi mevcut bir dizin olduğunda da, seçeneğinize ihtiyacınız olduğunu unutmayın .
Gilles 'SO- kötülük yapmayı bırak'

@Gilles - Benim tercihim, yansıtılmış bir hardlinks ağacı oluşturmak için komuttaki diğer küreleri kullanmak sh -c 'mkdir -p ../newtree/"$0"; ln "$0"/* ../newtree/$0 {} \;ve find -type ddaha sonra bunları kullanmaktı. Öncü / sondaki boşluklar hakkında iyi bir nokta olsa da, bunun da tercih edebileceğim bir davranış olduğunu düşünüyorum.
mikeserv

@Gilles - ama bu arada, bir değil cilvesi - amaçlanan ve bir standartlar kontrollü davranış. Saha-Bölme bölüm kelimeler içermiyorsa kabuk spec çok az arasındadır belirtilmemiş veya uygulama tanımlı . İle böyle bir garanti yoktur zsh'ın yerleşik işlevi zmv mesela.
mikeserv

2

PHP, 147 145 bayt, 2 1 boşluk 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);}}}

özyinelemeli işlev. İle koşs(".");

globVerilen yol için sonuçlar arasında geçiş yapın :

  • eğer dizin, tekrarla
  • alt çizgi ile boşlukları değiştir
  • dizeleri farklıysa
    • yeni dosya adı alınırken alt çizgi eklenir
    • dosya / dizini yeniden adlandır

php sunucudaki dosyaları yeniden adlandırır ... Şimdi bir müşterinin sitenizi ziyaret ettiklerinde dosya adlarını nasıl değiştireceğimi merak ediyorum: D
M.Herzkamp

1

Ruby 121

require 'find'

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

6
Code Golf'a Hoşgeldiniz! Bu kod golf mücadelesinde buradaki fikir , en az sayıda karakter kullanmaktır. Yani kesinlikle boş satırlar ve sekmeler kurtulmak ve değişken adları tek karakter yapmak, ama insanlar için bakmak anlamına gelir her türlü arasında yaratıcı yollar karakter sayımı azaltmak için.
Charles,

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
Dizinin

1

Python, 187

165, artı boşluklar için 22 ceza puanı.

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, Emanuele'nin numarasını kullanarak :

Bunda sadece bir boşluk var!

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

Bu benim için çalışıyor. +1
M.Herzkamp

satırların başındaki boşlukları kaldırın ve sekmeleri kullanın - bunlar boşluk değil, yalnızca bir kez sayılır
chill0r 13:14

@ chill0r Bu ikinci versiyonun ne olduğu; tüm boşluklar, biri hariç sekmelerle değiştirilir (SO dışında bunları hala boşluk olarak görüntüler).
Henry Keiter,

1

LiveScript - 166

(Boşlukları sekmelerle değiştirin.)

(a=->(s=require \fs)readdirSync(it)map (f)->f=it+'/'+f;r=f.replace /\s/g,i='';(while f!=r&&s.existsSync r=>r+=i++);s.statSync(f)isDirectory(s.renameSync f,r)&&a r) \.

Dayanarak nderscore en iyi duruma sürümü ait CPU1'in 'ın cevabı .


Eserleri! +1 Bu yazıyı düzeltmek için yorumlarımı daha önce sileceğim.
M.Herzkamp,

0

Bash 4+ 111 bayt

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

1
Diğer bazı girdilerle aynı problemler: Üst dizinlerdeki boşlukları değiştirdiniz ve mv bunları bulamıyor. Ayrıca hareket yönünü değiştirmelisiniz, aksi takdirde dizinleri yeniden adlandırırsınız ve mv içindeki dosyaları bulamaz.
M.Herzkamp

0

Harika, 139 karakter

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)

@ edc65 yoruma göre

Büyük, çarpışmalarla başa çıkma, 259 karakter

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
Bu çarpışmaları işlemez.
edc65

Üst dizinleri girmeden önce dosyaların yeniden adlandırıldığından ve üst dizinlerdeki boşlukların değiştirilmediğinden emin olun.
M.Herzkamp

Eminim tamam
giriş

0

POSIX (zsh'de test edilmiştir) + temel Linux komutları 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 Sabit.
LinGeek

Birkaç şey: ihracat IFS ve ls -cR'deki c'nin işlevi nedir? Ve mv hangi sürümü için ihtiyacınız var - cevap seçeneği? (8.13'üm var ve bu seçeneği tanımıyor). Ayrıca daha iyi bir skor elde etmek için değişken isimlerinizi kısaltmalısınız.
M.Herzkamp

C boşlukları yenileri ile değiştirir. IFS, boşlukları ayırıcı olarak durdurur. --Reply eski sürümlerden ve düzeltilmek üzere.
LinGeek

1
5. hatta ikinci bir mv mi kaçırıyorsun? Ve bence bu satırdaki bir yankı yanlış.
M.Herzkamp

1
$(ls -CR)tamamen sahtedir. Bu -cseçenek kullanışsızdır ve -Rdosyalarınızı dizinleri olmadan alır, ki bu anlamsızdır. Mimariniz temel olarak yeni satırlar içeren dosya adlarını işlemez. set -fJoker karakterler içeren dosya adlarına ihtiyacınız var yoksa patlayacak. exportişe yaramaz. Dosyaları benzersizleştirmek için ne yapmaya çalıştığınızı belli belirsiz görebiliyorum, ancak borular yanlış.
Gilles 'SO- kötülük' dur
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.