Bir metin dosyasının diğerinin alt kümesi olup olmadığını bilmek


12

Bir metin dosyasının başka bir alt küme olup olmadığını belirlemek için bir yol bulmaya çalışıyorum ..

Örneğin:

foo
bar

bir alt kümesidir

foo
bar
pluto

Süre:

foo
pluto

ve

foo
bar

birbirlerinin bir alt kümesi değildir ...

Bunu bir komutla yapmanın bir yolu var mı?

Bu kontrol bir çapraz kontrol olmalı ve geri dönmelidir:

file1 subset of file2 :    True
file2 subset of file1 :    True
otherwise             :    False

Potansiyel olarak daha verimli çözüm (dosyalar da sipariş edilirse
barrycarter

Yanıtlar:


11

Bu dosya içeriği çağırılmışsanız file1, file2ve file3apearance sırasına göre o zaman aşağıdaki tek satırlık yer ile yapabilirsiniz:

 # python -c "x=open('file1').read(); y=open('file2').read(); print x in y or y in x"
 True
 # python -c "x=open('file2').read(); y=open('file1').read(); print x in y or y in x"
 True
 # python -c "x=open('file1').read(); y=open('file3').read(); print x in y or y in x"
 False

Cevabınız için teşekkürler .. +1 .. Cevabımı kabul edip etmediğinizi bilmiyorum çünkü sizinkinin unix-linux'a özgü olmadığı ve cevabım test ettiğim kadar biraz daha hızlı .. ne düşünüyorsunuz?
gc5

Hoş geldiniz, elbette daha unix'e özgü araçlarla başka çözümler de var. Ama bu Python'un inoperatörünün iyi bir kullanımı gibi görünüyor .
Timo

Python komut satırı sarıcı, daha fazla unix gibi, yerleşik boru ile, pyp: code.google.com/p/pyp olarak adlandırılır. Bu çözümü bir astar aracı gibi daha unix yapmak önemsiz olduğunu düşünüyorum.
IBr

3

İle perl:

if perl -0777 -e '$n = <>; $h = <>; exit(index($h,$n)<0)' needle.txt haystack.txt
then echo needle.txt is found in haystack.txt
fi

-0octalKayıt sınırlayıcıyı tanımlar. Bu sekizlik sayı 0377'den (maksimum bayt değeri) büyük olduğunda, bu sınırlayıcı olmadığı anlamına gelir, buna eşdeğerdir $/ = undef. Bu durumda, <>tek bir dosyanın tam içeriğini döndürür, bu slurp modudur .

Dosyaların içeriğini iki $hve $ndeğişken olarak aldıktan sonra , index()birinin diğerinde bulunup bulunmadığını belirlemek için kullanabiliriz .

Ancak bu, tüm dosyaların bellekte depolandığı anlamına gelir; bu, bu yöntemin çok büyük dosyalar için çalışmayacağı anlamına gelir.

Mmappable dosyaları için (genellikle normal dosyaları ve blok aygıtlar gibi en çok aranabilir dosyaları içerir), perl modülü mmap()gibi dosyalar üzerinde çalışılarak çözülebilir Sys::Mmap:

if 
  perl -MSys::Mmap -le '
    open N, "<", $ARGV[0] || die "$ARGV[0]: $!";
    open H, "<", $ARGV[1] || die "$ARGV[1]: $!";
    mmap($n, 0, PROT_READ, MAP_SHARED, N);
    mmap($h, 0, PROT_READ, MAP_SHARED, H);
    exit (index($h, $n) < 0)' needle.txt haystack.txt
then
  echo needle.txt is found in haystack.txt
fi

2

Bu soru sayesinde bir çözüm buldum

Temelde iki dosyayı test ediyorum a.txtve b.txtbu script ile:

#!/bin/bash

first_cmp=$(diff --unchanged-line-format= --old-line-format= --new-line-format='%L' "$1" "$2" | wc -l)
second_cmp=$(diff --unchanged-line-format= --old-line-format= --new-line-format='%L' "$2" "$1" | wc -l)

if [ "$first_cmp" -eq "0" -o "$second_cmp" -eq "0" ]
then
    echo "Subset"
    exit 0
else
    echo "Not subset"
    exit 1
fi

Bir başka senaryo getiri alt küme halinde 0için Trueaksi 1.


% L ne yapar? Bu komut dosyası işe yaramıyor ve hata ayıklamaya çalışıyorum ...
Alex

Aslında anlamını hatırlamıyorum %L, üç yıl önceydi. Kimden man diff(geçerli sürüm) %L"satır içeriği" anlamına gelir.
gc5

% L "yeni" satırın içeriğini yazdırır. IOW, değişmeyen satırlar veya eski satırlar için hiçbir şey yazdırmayın, ancak satırın içeriğini yeni satırlar için yazdırın.
PLG

Bu senaryo benim için çalışıyor, kutudan çıkar!
PLG

2

F1, f2'nin bir alt kümesiyse f1 - f2, boş bir kümedir. Buna dayanarak bir is_subset işlevi ve bundan türetilen bir işlev yazabiliriz. Gereğince Seti farkı 2 metin dosyaları arasında


sort_files () {
  f1_sorted = "$ 1.sorted"
  f2_sorted = "$ 2.sorted"

  Eğer [ ! -f $ f1_sorted]; sonra
    kedi 1 $ | sırala | uniq> $ f1_sorted
  fi

  Eğer [ ! -f $ f2_sorted]; sonra
    kedi 2 $ | sırala | uniq> $ f2_sorted
  fi
}

remove_sorted_files () {
  f1_sorted = "$ 1.sorted"
  f2_sorted = "$ 2.sorted"
  rm -f $ f1_sorted
  rm -f $ f2_sorted
}

set_union () {
  sort_files $ 1 $ 2
  kedi "$ 1.sorted" "$ 2.sorted" | sırala | uniq
  remove_sorted_files $ 1 $ 2
}

set_diff () {
  sort_files $ 1 $ 2
  kedi "$ 1.sorted" "$ 2.sorted" "$ 2.sorted" | sırala | uniq -u
  remove_sorted_files $ 1 $ 2
}

rset_diff () {
  sort_files $ 1 $ 2
  kedi "$ 1.sorted" "$ 2.sorted" "$ 1.sorted" | sırala | uniq -u
  remove_sorted_files $ 1 $ 2
}

is_subset () {
  sort_files $ 1 $ 2
  çıktı = $ (set_diff $ 1 $ 2)
  remove_sorted_files $ 1 $ 2

  eğer [-z $ output]; sonra
    dönüş 0
  Başka
    dönüş 1
  fi

}


Bu komut dosyası ile başlamalı #!/bin/bashmı?
Alex

2

Gönderen http://www.catonmat.net/blog/set-operations-in-unix-shell/ :

Comm iki sıralı dosyayı satır satır karşılaştırır. Yalnızca ilk belirtilen dosyada görünen satırları çıkaracak şekilde çalıştırılabilir. İlk dosya ikincinin alt kümesiyse, 1. dosyadaki tüm satırlar da 2.'de görünür, bu nedenle çıktı üretilmez:

$ comm -23 <(sort subset | uniq) <(sort set | uniq) | head -1
# comm returns no output if subset ⊆ set
# comm outputs something if subset ⊊ set
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.