Bir dosyadaki 6 karakterden kısa tüm satırları nasıl kaldırabilirim?


17

Yaklaşık 10 milyon satır içeren bir dosyam var.

Dosyadaki altı karakterden daha az olan tüm satırları kaldırmak istiyorum.

Bunu nasıl yaparım?


Bu soru Stackoverflow için daha uygun değil mi?
user1073075

2
@ user1073075 burada mükemmel bir konudur.
Seth

Yanıtlar:


30

Bunu yapmanın birçok yolu var.

Kullanma grep:

grep -E '^.{6,}$' file.txt >out.txt

Şimdi out.txtaltı veya daha fazla karakter içeren satırlar olacak.

Ters yol:

grep -vE '^.{,5}$' file.txt >out.txt

sed5 veya daha küçük uzunluktaki hatları kullanarak , kaldırarak:

sed -r '/^.{,5}$/d' file.txt

Ters yol, altı veya daha fazla uzunluktaki baskı hatları:

sed -nr '/^.{6,}$/p' file.txt 

Çıkışı farklı bir dosyaya >operatör kullanarak kaydedebilir grepveya aşağıdaki -iseçeneği kullanarak dosyayı yerinde düzenleyebilirsiniz sed:

sed -ri.bak '/^.{6,}$/' file.txt 

Orijinal dosya olarak yedeklenir file.txt.bakve değiştirilen dosya olur file.txt.

Yedek tutmak istemiyorsanız:

sed -ri '/^.{6,}$/' file.txt

Kabuk kullanma, Yavaş, Bunu yapma , bu sadece başka bir yöntem göstermek uğruna:

while IFS= read -r line; do [ "${#line}" -ge 6 ] && echo "$line"; done <file.txt

Kullanılması python, hatta daha yavaş grep, sed:

#!/usr/bin/env python2
with open('file.txt') as f:
    for line in f:
        if len(line.rstrip('\n')) >= 6:
            print line.rstrip('\n')

Daha Pitonik olmak için liste kavrayışını daha iyi kullanın:

#!/usr/bin/env python2
with open('file.txt') as f:
     strip = str.rstrip
     print '\n'.join([line for line in f if len(strip(line, '\n')) >= 6]).rstrip('\n')

Yaşasın! Bir python cevabı bekliyordum =)
TellMeWhy,

@DevRobot Anlıyorum .. o zaman liste kavrama kontrol ekledi, daha Pythonic olun ..
heemayl

1
Ayrıca @DevRobot ilk seçenek kullanıldığında, büyük dosyalarda python yavaş olduğundan emin değil. Aslında python'un milyonlarca satırda daha hızlı olduğundan eminim, çünkü satır başına okuyor.
Jacob Vlijm

1
İkinci python örneği, birleştirme yapmadan önce tüm dosyayı belleğe okur. İlk python örneği bu durumda daha iyi olduğunu düşünüyorum.
Holloway

Dosyalar bu şekilde yapılandırılmadığından satırlarla okuma mutlaka daha yavaştır. Yine de ileride bir blok okumalı ve paralellik olasılığını azaltan yeni bir satır aramalısınız, sonra sadece kısmi dizeyi döndürmelisiniz. Dairesel bir tampona ihtiyacınız var. Hatların ne kadar sürebileceğini bilmiyorsanız, belleği dinamik olarak ayırmanız gerekir.
Vee

19

Çok basit:

grep ...... inputfile > resultfile   #There are 6 dots

Bu şekilde, son derece verimli olduğunu grepgerekenden fazla ayrıştırmak denemez, ne de herhangi bir şekilde karakter yorumlamak: basitçe Stdout'a bir (bütün) hattını (kabuk sonra resultfile adresine yönlendirir) göndermek en kısa sürede o 6 gördü bu satırdaki .grafikler ( normal ifade bağlamında herhangi bir 1 karakterle eşleşir).

Bu nedenle grep, yalnızca 6 (veya daha fazla) karakter içeren satırlar çıkarır ve diğeri grep tarafından çıktılanmaz, böylece sonuç dosyasına ulaşmazlar.


14

1.Çözüm: C Kullanımı

En hızlı yol: Bu C programını derleyin ve çalıştırın:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_BUFFER_SIZE 1000000

int main(int argc, char *argv[]) {
    int length;

    if(argc == 3)
        length = atoi(argv[2]);
    else
        return 1;

    FILE *file = fopen(argv[1], "r");

    if(file != NULL) {
        char line[MAX_BUFFER_SIZE];

        while(fgets(line, sizeof line, file) != NULL) {
            char *pos;

            if((pos = strchr(line, '\n')) != NULL)
                *pos = '\0';
            if(strlen(line) >= length)
                printf("%s\n", line);
        }

        fclose(file);
    }
    else {
        perror(argv[1]);
        return 1;
    }

    return 0;
}

İle derleyin gcc program.c -o program, ile çalıştırın ./program file line_length(burada file= dosya yolu ve line_length= minimum satır uzunluğu, sizin durumunuzda 6; maksimum satır uzunluğu 1000000satır başına karakterlerle sınırlıdır ; değerini değiştirerek değiştirebilirsiniz MAX_BUFFER_SIZE).

( Burada bulunan \nile değiştirme hilesi .)\0

Kabuk çözümü hariç bu soruya önerilen tüm diğer çözümlerle karşılaştırma (ortalama uzunluğu 8 karakter olan 10M satırlı ~ 91MB dosyada test çalıştırması):

time ./foo file 6

real    0m1.592s
user    0m0.712s
sys 0m0.160s

time grep ...... file

real    0m1.945s
user    0m0.912s
sys 0m0.176s

time grep -E '^.{6,}$'

real    0m2.178s
user    0m1.124s
sys 0m0.152s

time awk 'length>=6' file

real    0m2.261s
user    0m1.228s
sys 0m0.160s

time perl -lne 'length>=6&&print' file

real    0m4.252s
user    0m3.220s
sys 0m0.164s

sed -r '/^.{,5}$/d' file >out

real    0m7.947s
user    0m7.064s
sys 0m0.120s

./script.py >out
real    0m8.154s
user    0m7.184s
sys 0m0.164s

Çözüm # 2: AWK Kullanımı:

awk 'length>=6' file
  • length>=6: length>=6DOĞRU döndürürse, geçerli kaydı yazdırır.

Çözüm # 3: Perl Kullanımı:

perl -lne 'length>=6&&print' file
  • Eğer lenght>=6döner DOĞRU, geçerli kaydı yazdırır.

% cat file
a
bb
ccc
dddd
eeeee
ffffff
ggggggg
% ./foo file 6
ffffff
ggggggg
% awk 'length>=6' file   
ffffff
ggggggg
% perl -lne 'length>=6&&print' file
ffffff
ggggggg

1
Me..I bekliyordu Believe sizin awk çözümü ..
heemayl

2
@heemayl Ve soruyu hemen görmedim, bu yüzden çevrimiçi olsaydınız daha hızlı olacağını biliyordum . sedÇözümümü silmek zorunda kaldım (olur, biliyorum). XD
Kos

posDeğişkenin anlamı nedir ? lineNewline karakteriyle karaktere bir işaretçi döndürür , ama asla kullanmıyormuş gibi görünüyorsunuz. Ve bulamazsanız, sadece ona eşitlersiniz \0.
user1717828

@ user1717828 Eğer bulursam onunla değiştiririm \0( strchr()karakter bulunmazsa NULL işaretçisi döndürür ). Buradaki nokta, her satırın sonundaki her satırın yerini \0, satırsonu asla sayılmayacak şekilde değiştirmektir strlen(): bu, son satırdaki potansiyel eksik satırdan bağımsız olarak uzunluk her zaman 6 ile karşılaştırılabilir. Sadece son çizgiye farklı davranmak çok daha verimli olur. Muhtemelen bunu daha sonra güncelleyeceğim.
kos

1
@tripleee Fikir, bir kerelik bir işten daha fazlası veya daha büyük dosyalar için yararlı bir çözüm eklemekti, ancak : grepAynı dosyada çözümü test ettim ve aslında daha hızlı (muhtemelen strlen()burada en iyi fikir olmadığı için) . Bunun getchar()yerine sadece ilk N karakterini kontrol etmek için bir döngü kullanmaya çalışacağım , sanırım bunu gözle görülür şekilde geliştirmeliyiz. Ve evet, tamponun uzunluğu üzerindeki herhangi bir çizgi sadece tamponun uzunluğuna kesilir.
kos

2

Vim'i Ex modunda kullanabilirsiniz:

ex -sc 'v/\v.{6}/d' -cx file
  1. \v sihri aç

  2. .{6} 6 veya daha fazla karakter içeren satırları bulma

  3. v zıt seçim

  4. d silmek

  5. x kaydet ve kapat


1

Ruby çözümü:

$ cat input.txt                                                                                                          
abcdef
abc
abcdefghijk

$ ruby -ne 'puts $_ if $_.chomp.length() >= 6 ' < input.txt                                                              
abcdef
abcdefghijk

Basit fikir: dosyayı ruby'nin stdin'e yönlendirin ve stdin'den sadece 6 veya daha büyük bir uzunluksa satır yazdırın

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.