ファイルBの文字列を含むファイルAのすべての行を削除します。

ファイルBの文字列を含むファイルAのすべての行を削除します。

users.csvユーザー名、ユーザーID、およびその他のデータのリストを含むCSVファイルがあります。

username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"Paul McCartny", 30923833, "left", "black"
"Ringo Starr", 77392318, "right", "blue"
"George Harrison", 72349482, "left", "green"

他のファイルにはtoremove.txtユーザーIDのリストがあります。

30923833
77392318

users.csvファイルからIDを含むすべての行を削除するスマートで効率的な方法はありますかtoremove.txt?私はこれらの2つのファイルを解析し、新しいファイルにない行だけを書く単純なPythonアプリケーションを書いたが、toremove.txt非常に遅い。たぶんsed魔法はawkここに役立つでしょうか?

上記の例を考慮すると、望ましい結果は次のとおりです。

username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"

答え1

を使用すると、grep次のことができます。

$ grep -vwF -f toremove.txt users.txt 
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"

そしてawk

$ awk -F'[ ,]' 'FNR==NR{a[$1];next} !($4 in a)' toremove.txt users.txt 
username, userid, sidebar_side, sidebar_colour
"John Lennon", 90123412, "left", "blue"
"George Harrison", 72349482, "left", "green"

答え2

awk空間盲のために修正されたGnoucの答えは次のとおりです。

awk -F, 'FNR==NR{a[$1];next} !(gensub("^ *","",1,$2) in a)' toremove.txt users.csv

区切り文字としてはスペース以外のカンマのみを使用するため、対応するスペース(ユーザーID)がファイルに存在することを確認する前に、先行スペースを削除してください$1"John Lennon"$2 90123412gensub$2toremove.txt

答え3

良いルビー方法:あるファイルに文字列リストがあり、別のファイルのすべての行を削除したい場合含む最初のファイルの文字列(この場合は「file1」から「file2」を削除)Rubyファイル:

b=File.read("file2").split # subtract this one out
remove_regex = Regexp.new(b.join('|'))
File.open("file1", "r").each_line do |line|
  if line !~ remove_regex
    puts line
  end
end

残念ながら、これは「削除する」大きなファイルの複雑さをO(N ^ 2)に減らすようですが(私の仮定は正規表現が行うことが多いと仮定しています)、まだ誰かに役立つかもしれません(もし行全体を削除する以上のものが欲しい)場合によってはより速いかもしれません。

速度を追求する場合、別のオプションは同じハッシュチェックメカニズムを使用することです。ただし、一致する文字列があるかどうかを注意深く「構文解析」してから、ハッシュと比較します。

Rubyでは、次のように見えます。

b=File.read("file2").split # subtract this one out
hash={}
for line in b
  hash[line] = 1
end

ARGF.each_line do |line|
  ok = true
  for number in line.scan(/\d{9}/)
    if hash.key? number
      ok=false
    end
  end
  if (ok)
    puts line
  end
end

ここで提案されているawkの回答に似ており、O(N ^ 2)の複雑さ(休)を避けるScottの回答も参照してください。

関連情報