Boş satırları kaldırmak için bir metin dosyasını filtrelemenin iyi bir yolu nedir?


11

Bir sürü boş satır, örneğin bir .csv dosyası (mac) var:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum 

lorem ipsum ","2","3","4"

Hangi dönüştürmek istiyorum:

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum  lorem ipsum ","2","3","4"

Tek bir astar olması gerektiğini biliyorum ama awk veya sed bilmiyorum. Herhangi bir ipucu büyük takdir!


1
Bu örneğe göre, aslında gömülü satır sonlarını alanlardan kaldırmak istiyorsunuz. Bu doğru mu? Başka bir deyişle, 6 giriş hattı vardır ve 2 çıkış hattı olmalıdır?
manatwork

Evet, tam olarak bundan kurtulmaya çalışıyorum: alıntılanan bir dizenin içine gömülü yeni satırlar.
pitosalas

Yani ihtiyacınız olan şey tırnak içindeki satırları kaldıran bir şey. Bu biraz daha karmaşık olacak, çünkü çok satırlı regex'e ihtiyacınız var.
tongpu

Yanıtlar:


11

Bunu yapmak için grep'in -v(tersine eşleme) modunu kullanabilirsiniz:

grep -v '^$' old-file.csv > new-file.csv

Kabuk yönlendirmelerinin çalışma şekli nedeniyle bunların farklı dosyalar olması gerektiğini unutmayın. Giriş dosyası okunmadan önce çıktı dosyası açılır (ve boşaltılır). Daha fazla ağınız varsa (Mac OS X'te varsayılan olarak değil), bu soruna spongegeçici bir çözüm bulmak için kullanabilirsiniz :

grep -v '^$' file.csv | sponge file.csv

Ama elbette, bir şeyler ters giderse geri dönmekte zorlanıyorsunuz.

"Boş satırlar" aslında boşluklar içeriyorsa (göründüğü gibi), bunun yerine bunu kullanabilirsiniz:

egrep -v '^[[:space:]]*$' old-file.csv > new-file.csv

Bu, boş satırları ve yalnızca boşluk içeren satırları yok sayar. Tabii ki aynı spongedönüşümü de yapabilirsiniz.


Teşekkürler .... Boş satırları silmediniz ... Belki ^ $ eşleşmiyor mu? Ama çizgiler bilgim dahilinde boş. Unutmayın bu bir mac üzerinde excel tarafından oluşturulan bir cdv ... Bu bir şey söylüyor mu? (Excel dedim çünkü çığlık
atmayın

@pitosalas Muhtemelen boş çizgiler değiller. egrep -v '^[[:space:]]*$'Not grep -> egrep ve garip yeni deseni değiştirmeyi deneyin
derobert

İşe yaramadı. Bir çift çift tırnak
silindi

@pitosalas Çift tırnakları nasıl sileceğinden emin değilim. Yalnızca boşlukları silebilmelidir. Ve gerçekten, gönderdiğin örnek veriler üzerinde test ettiğimde bunu yapar ...
derobert

@pitosalas bu komutlardan birinin makul göründüğünü (anlamsızca aksine) tükürüp tükürmediğini kontrol edebilir misiniz: iconv -f utf16le file.csv | headveyaiconv -f utf16be file.csv | head
derobert

8

En kolay seçenek sadece grep .. Burada nokta "her şeyi eşleştir" anlamına gelir, bu nedenle çizgi boşsa eşleşmez. Aksi takdirde tüm satırı olduğu gibi yazdırır.


6

Ksh93 ile yerinde boş satırları kaldırmak için :

sed '/./!d' file 1<>; file

Yeniden <>;yönlendirme işleci ksh93'e özgüdür ve <>ksh komutun sona erdirilmesinden sonra dosyayı kesmesi dışında standart işleç ile aynıdır.

sed '/./!d'yazmanın kıvrımlı bir yoludur grep ., ancak maalesef GNU grep en azından stdout'u stdin ile aynı dosyayı gösteriyorsa şikayet eder. Birinin yazabileceğini söylerdiniz:

grep . file | cat 1<>; file

Ancak ne yazık ki, ksh93'te (en azından benim sürümüm (93u +)) bir hata var, bu durumda dosya sıfır uzunluğa kesilmiş gibi görünüyor.

grep . file | { cat; } 1<>; file

Bu böceğin etrafında çalışmak gibi görünüyor, ama şimdi, sed komutundan çok daha kıvrımlı.


Lütfen yanıtlarınızı her bir çözümün ne zaman kullanılması gerektiğine ilişkin hızlı bir kılavuzla iyi biçimlendirilmiş bir girişte birleştirin. Değişen cevaplarda bir araya gelen farklı sorunlara farklı yaklaşımlar, bu soruyu okumak için bir felaket haline getirdi.
Caleb

@Caleb, Her şey sorunun çok belirsiz olmasına bağlı, bu yüzden herkesin cevapları sorunun farklı yorumları içindir. Her cevap için hangi soruyu cevaplamaya çalıştığını söylemeye çalıştım.
Stéphane Chazelas

Sadece FYI: awk '/./' file 1<>; fileHangi işe yaradığını denedim . Bana göre, bu daha da netsed '/./!d'
grebneke

5

İşte Perlbunun için bir astar:

perl -pi -e 's/^\s*\n//' yourfile

DÜZENLEME: ruakh'ın aşağıdaki yorumlarına dayanan kod geliştirildi.


1
Veyaperl -ni -e '/./ and print' yourfile
derobert

1
@peterph $bir çapa (yani sıfır genişlikli) olduğundan satırsonu hariçtir. Gereksiz alana gelince, regex'e `$ \ 'eklemeyi denemek /xistemedimPerl
Joseph R.

1
Sahip $olduğunuz göz önüne alındığında, ihtiyacınız yoktur \n. (Alternatif olarak \n, \s*ve 'ye sahip olduğunuz göz önüne alındığında buna ihtiyacınız yoktur $; ancak bence s/^\s*\n//yeni satırın kaldırıldığını daha da netleştirir.) Ayrıca /m; bu komut üzerinde hiçbir etkisi yoktur. Ve bir kez $ve alandan kurtulduğunuzda, ihtiyacınız olmayacak /x.
ruakh

1
@JosephR .: \nkendisi olabilir çıkarılabilir; ne yapamaz kaldır olduğunu hem $ ve\n . Yani s/^\s*//tarif ettiğiniz sorun s/^\s*$//olurdu , ama iyi olurdu, çünkü \s*ve $. (Ne demek istediğimi anlıyor musun?)
ruakh

1
, Olan ne olur @JosephR .: $ edebilir bir satır önce eşleşmesi (ya şartıyla /mbayrağı etkinleştirildiğinde veya yeni satır dize en son karakteridir veya her ikisi), ancak olabilir ayrıca dizenin sonunu maç. Örneğin "abc" =~ m/^abc$/, doğrudur. Durumunda \s*$, \s*yeni satır yemeye açgözlü yeterlidir ve ardından $son-of-string eşleşir. (Ama s/^\s*\n//yine de daha net olduğunu düşünüyorum , bu yüzden cevabınız şimdi olduğu gibi iyi.)
ruakh

5

Sorunuzun yorumlarındaki açıklamaya dayanarak, aşağıdaki gibi bir şey:

awk -v RS= -v ORS= 1

ne istersen yapabilir.

Boş bir kayıt ayırıcı , awkkayıtların paragraf (boş satır dizileriyle ayrılmış) olacağını söyleyen özel bir durumdur . Çıktı kaydı ayırıcısının da boş dizeye ayarlanması, bu paragrafların içeriğinin (ayırıcılar olmadan) birleştirileceği anlamına gelir. her kaydı basmak 1için gerçek bir koşuldur.

Ancak bu, sondaki yeni satırı atlar, böylece şunları yapabilirsiniz:

awk -v RS= -v ORS= '1;END{if (NR) printf "\n"}'

3

Dosyayı verirsem bunun daha kolay olacağını biliyorum, ancak maalesef paylaşamayacağım gizli bilgiler içeriyordu. Bu arada bana hile gibi görünen yakut bir senaryo yazdım:

require 'csv'
c = CSV.open("outfile1.csv", "w")
CSV.foreach("data.csv", :encoding => 'windows-1251:utf-8') do |row|
  row = row.map { |a| a.class == String ? a.gsub(/\r/, '') : a}
  c << row
end
c.close

Herkese yardım ettiği için teşekkürler!


2
awk '
    length == 0 {next} 
    /^[^"]/ && /"$/ {print; next} 
    {printf("%s", $0)}
' filename

üretir

"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"

2

Stackoverflow üzerinde olası bir çözüm için bir fikir buldum .

sed -i ':a;N;$!ba;s/[^"]\n\s*\n/ /g' file.csv

Muhtemelen test etmeden önce csv dosyanızı yedeklemelisiniz, ancak en azından sağladığınız örnek için kusursuz bir şekilde çalışır.

Bu ifadenin iç işleyişi hakkında iyi bir açıklama cevapta sunulmaktadır, sadece bir "( [^"]\n) ile bitmeyen satırları aramak için düzenledim .


1

Kendi yanıtınızdan alıntılanan dizelerin içindeki yeni satır karakterlerini kaldırmak istiyorsanız şunları yapabilirsiniz:

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse'

-iDosyaları yerinde düzenlemek için perl bayrağını da kullanabilirsiniz .

 perl -0777 -pe 's/".*?"/$_=$&;s:\n::g;$_/gse' file1 file2...

Veya GNU awk ile:

 awk -v RS=\" 'NR%2==0 {gsub("\n","")}; {printf "%s", $0 RT}'

veya:

 awk -vRS=\" '1-NR%2{gsub("\n","")}{ORS=RT}1'

(en kısa olan için yarışıyorsanız)

O hiçbir orada olduğunu varsayalım o Not kaçan girişinde çift tırnak karakterleri.


0

Görünüşe göre boş satırları kaldırmaktan daha fazlasını istiyorsunuz, ancak 2 veya daha fazla yeni satır karakteri içeren her diziyi kaldırın.

Perl ile yapabileceğiniz:

perl -0777 -pe 's/\n{2,}//gs' file

-iDosyaları yerinde düzenlemek için perl bayrağını da kullanabilirsiniz .

perl -0777 -pi -e 's/\n{2,}//gs' file1 file2...

0

Boş satırları kaldırmanın daha kısa bir yolu vardır AWK:

awk 'NF' file

Ancak istediğiniz çıktıyı elde etmek için gereken tek şey basit bir astardır:

awk 'NF {printf("%s ", $0); i++;} !(i % 2) {printf("\n");}' file

açıklama

İçinde AWKboş bir satır, satır / kaydın hiç alanı olmadığı, yani NF(Alan Sayısı) değişkeninin sıfır olduğu anlamına gelir. Yukarıdaki bir astar yalnızca NF > 0tüm satırları yazdırırken, ancak boş satırları yazdırırken çalışır.

i++Boş olmayan çizgileri sayacı.

Bu !(i % 2), ardışık iki boş satırı istediğiniz çıktıya göre yazdırmak için kullanılır, yani 2'nin katları her bulunduğunda, moduloifade !(i % 2)boş olmayan iki satırın bitişini sona erdiren 1 verir.


Benim hatam! Üzgünüm. Bütün sorusunu ve istenen çıktıyı okumadım. Yanıt düzeltildi. Teşekkürler. :-)
Marcelo Augusto

0

Vim'i Ex modunda kullanabilirsiniz:

ex -sc v/./d -cx b.csv
  1. v/./ boş çizgiler bul

  2. d silmek

  3. x kaydet ve kapat

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.