Як дізнатися, чи є текстовий файл підмножиною іншого


12

Я намагаюся знайти спосіб визначити, чи є текстовий файл підмножиною іншого ..

Наприклад:

foo
bar

є підмножиною

foo
bar
pluto

Поки:

foo
pluto

і

foo
bar

не є підмножиною один одного ...

Чи є спосіб це зробити за допомогою команди?

Цей чек повинен бути перехресним і він повинен повертати:

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

Потенційно більш ефективне рішення (якщо файли також замовлені): github.com/barrycarter/bcapps/blob/master/…
barrycarter

Відповіді:


11

Якщо цей вміст файлу викликається file1, file2і file3в порядку появи, ви можете зробити це за допомогою наступного однокласника:

 # 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

Дякую за вашу відповідь .. +1 .. Я не знаю, чи прийміть мою відповідь, оскільки ваша не є специфічною для unix-linux, і моя відповідь трохи швидше, наскільки я перевірив її .. що ви думаєте?
gc5

Запрошуємо, звичайно, є й інші рішення з більш уніфікованими інструментами. Але це здається хорошим використанням inоператора Python .
Тимо

Існує обгортка командного рядка python, щоб зробити його більш схожим на Unix, із вбудованими трубопроводами під назвою pyp: code.google.com/p/pyp. Я думаю, що це банально зробити це рішення більш unix, як один інструмент для вкладок .
IBr

3

З 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

-0octalвизначає роздільник запису. Коли число восьмериків більше 0377 (максимальне значення байта), це означає, що немає роздільника, це рівнозначно виконанню $/ = undef. У такому випадку <>повертається повний вміст одного файлу, ось режим "slurp" .

Як тільки ми вмістимо файли у двох $hта $nзмінних, ми можемо використовувати, index()щоб визначити, чи знайдено один в іншому.

Однак це означає, що цілі файли зберігаються в пам'яті, що означає, що метод не працюватиме для дуже великих файлів.

Для файлів mmappable (як правило, це звичайні файли та найбільш видимі файли, такі як блокові пристрої), які можна обробити за допомогою mmap()файлів, як-от за допомогою Sys::Mmapмодуля perl:

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

Я знайшов рішення завдяки цьому питанню

В основному я тестую два файли a.txtі b.txtз цим сценарієм:

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

Якщо одне є підмножиною іншого, сценарій повернеться 0для Trueіншого 1.


Що робить% L? Цей сценарій, здається, не працює, і я намагаюся налагодити його ...
Алекс

Я насправді не пам'ятаю сенсу %L, це було три роки тому. З man diff(поточна версія) %Lозначає "вміст рядка".
gc5

% L друкує вміст "нового" рядка. IOW, не друкуйте нічого для незмінних чи старих рядків, але друкуйте вміст рядка для нових рядків.
PLG

Цей сценарій працює для мене, поза коробкою!
PLG

2

Якщо f1 є підмножиною f2, то f1 - f2 - порожній набір. Спираючись на це, ми можемо записати функцію is_subset і функцію, похідну від неї. Відповідно до встановлення різниці між 2 текстовими файлами


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

  якщо [! -f $ f1_sorted]; потім
    кішка $ 1 | сортувати | uniq> $ f1_sorted
  фі

  якщо [! -f $ f2_sorted]; потім
    кішка $ 2 | сортувати | uniq> $ f2_sorted
  фі
}

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
  cat "$ 1.sorted" "$ 2.sorted" | сортувати | uniq
  Remove_sorted_files $ 1 $ 2
}

set_diff () {
  sort_files $ 1 $ 2
  cat "$ 1.sorted" "$ 2.sorted" "$ 2.sorted" | сортувати | uniq -u
  Remove_sorted_files $ 1 $ 2
}

rset_diff () {
  sort_files $ 1 $ 2
  cat "$ 1.sorted" "$ 2.sorted" "$ 1.sorted" | сортувати | uniq -u
  Remove_sorted_files $ 1 $ 2
}

is_subset () {
  sort_files $ 1 $ 2
  вихід = $ (set_diff $ 1 $ 2)
  Remove_sorted_files $ 1 $ 2

  якщо [-z $ вихід]; потім
    повернути 0
  ще
    повернути 1
  фі

}


Слід почати цей сценарій #!/bin/bash?
Олексій

2

Від http://www.catonmat.net/blog/set-operations-in-unix-shell/ :

Comm порівнює два відсортованих файли по черзі. Він може бути запущений таким чином, що він виводить рядки, які відображаються лише в першому вказаному файлі. Якщо перший файл є підмножиною другого, то всі рядки в 1-му файлі також з'являються у 2-му, тому вихід не виробляється:

$ comm -23 <(sort subset | uniq) <(sort set | uniq) | head -1
# comm returns no output if subset ⊆ set
# comm outputs something if subset ⊊ set
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.