ファイル内の6文字未満のすべての行を削除するにはどうすればよいですか?


17

約1,000万行のファイルがあります。

ファイル内の6文字未満のすべての行を削除したい。

どうすればいいですか?


この質問はStackoverflowにより適していませんか?
user1073075

2
@ user1073075ここでは完全に話題になっています。
セス

回答:


30

これを行うには多くの方法があります。

を使用してgrep

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

これでout.txt、6文字以上の行が含まれます。

逆の方法:

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

を使用してsed、長さ5以下の行を削除します。

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

長さ6以上の行を印刷する逆の方法:

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

>ような演算子を使用して出力を別のファイルに保存するgrep-ised次のオプションを使用してその場でファイルを編集できます。

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

元のファイルはとしてバックアップされfile.txt.bak、変更されたファイルはとしてバックアップされますfile.txt

バックアップを保持したくない場合:

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

シェルを使用して、遅い、これをしないでください、これは別の方法を示すためだけです:

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

使用してpython、さらに遅いよりもgrepsed

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

リスト内包表記を使用してPythonicにする方が良い:

#!/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')

わーい!Pythonの答えを期待していた=)
TellMeWhy

@DevRobotわかりました。それから、リストの内包表記をチェックアウトして、もっとPythonicになってください
。– heemayl

1
また、@ DevRobotは、最初のオプションが使用されている場合、Pythonが巨大なファイルで遅いことを確信できません。実際、Pythonは1行ごとに読み取るため、数百万行で高速になると確信しています。
ジェイコブVlijm

1
2番目のpythonの例では、結合を実行する前にファイル全体をメモリに読み込みます。この場合、最初のpythonの例の方が優れていると思います。
ホロウェイ

ファイルがそのように構成されていないため、行による読み取りは必然的に遅くなります。とにかく先のブロックを読み、並列化の可能性を減らした改行を検索し、部分文字列のみを返す必要があります。循環バッファが必要です。行の長さがわからない場合は、メモリを動的に割り当てる必要があります。
ヴィー

19

とても簡単です:

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

これは、非常に効率的でgrepより多くのそれは必要以上に解析しようとはしません、またどのような方法で文字を解釈するために:それは単に(シェルは、その後resultfileにリダイレクト)標準出力に(全体)の行を送るとすぐにそれが6を見ましたその行の文字(.正規表現コンテキストでは任意の1文字に一致します)。

そのため、grepは6文字以上の行のみを出力し、他の行はgrepによって出力されないため、結果ファイルになりません。


14

解決策1:Cを使用する

最速の方法:このCプログラムをコンパイルして実行します。

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

でコンパイルしgcc program.c -o program./program file line_length(ここでfile=ファイルへのパスとline_length=最小行の長さ、あなたの場合6、最大行の長さは10000001行あたりの文字数に制限されます。これを変更するには、MAX_BUFFER_SIZE)。

ここ\n\0見つかっと置き換えるトリック)

シェルソリューションを除く、この質問に対して提案された他のすべてのソリューションとの比較(8文字の平均長で10M行の〜91MBファイルでテストを実行):

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

解決策2:AWKを使用する:

awk 'length>=6' file
  • length>=6length>=6TRUEを返す場合、現在のレコードを印刷します。

解決策3:Perlを使用する:

perl -lne 'length>=6&&print' file
  • lenght>=6TRUEを返す場合、現在のレコードを印刷します。

% 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
私を信じて..私はあなたの awk解決を待っていた
..-heemayl

2
@heemaylそして、私はすぐに質問を見なかったので、もしあなたがたまたまオンラインにたなら、あなたはより速くなるだろうと知っていました。私のsed解決策を削除しなければなりませんでした(それは起こります)。XD-
コス

pos変数のポイントは何ですか?私はそれがline改行文字で文字へのポインタを返しますが、あなたはそれを使用することはないようです。見つからない場合は、に等しく設定し\0ます。
user1717828

@ user1717828見つかったらそれを置き換えます\0strchr()文字見つからない場合はNULLポインターを返します)。ポイントは、各行の終わりにある各改行をで置き換え\0て、改行がカウントされないようにしますstrlen()。これは、最後の行で改行が欠落している可能性に関係なく、長さを常に6と比較できるようにするためです。最後の行だけを別の方法で処理すると、はるかに効率的になります。おそらく後で更新します。
コス

1
@tripleeeアイデアがよりワンタイムの仕事よりも何かのために有用、またはさらに大きなファイルのためのソリューションを追加することでした、しかし、私はテストしたgrep同じファイルのソリューションを、それが実際に高速です(おそらくためには、strlen()ここでは最高のアイデアではありません) 。getchar()代わりに、最初のN文字のみをチェックするためにループを使用してみます。これにより、目に見える形で改善されるはずです。そして、はい、バッファーの長さを超える行はバッファーの長さに合わせて切り取られます。
コス

2

ExモードでVimを使用できます。

ex -sc 'v/\v.{6}/d' -cx file
  1. \v 魔法をつける

  2. .{6} 6文字以上の行を見つける

  3. v 選択を反転

  4. d 削除する

  5. x 保存して閉じます


1

Rubyソリューション:

$ cat input.txt                                                                                                          
abcdef
abc
abcdefghijk

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

シンプルなアイデア:ファイルをrubyのstdinにリダイレクトし、長さが6以上の場合にのみstdinから行を出力する

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.