จะทราบได้อย่างไรว่าไฟล์ข้อความเป็นส่วนย่อยของอีกไฟล์หนึ่ง


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ในคำสั่งของ apearance แล้วคุณสามารถทำมันได้ด้วยดังต่อไปนี้หนึ่งซับ:

 # 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 .. ฉันไม่ทราบว่าถ้ายอมรับคำตอบของฉันเพราะคุณไม่ใช่ยูนิกซ์ลินุกซ์ที่เฉพาะเจาะจงและคำตอบของฉันนั้นเร็วกว่านี้ตราบใดที่ฉันทดสอบมัน .. คุณคิดอย่างไร?
gc5

คุณยินดีต้อนรับมีหลักสูตรการแก้ปัญหาอื่น ๆ ที่มีเครื่องมือเฉพาะยูนิกซ์เพิ่มเติม แต่นี่ดูเหมือนจะเป็นการใช้งานที่ดีของโอเปอร์inเรเตอร์งูใหญ่
Timo

มีไพเพอร์บรรทัดคำสั่งของ python เพื่อทำให้มันเป็นเหมือนยูนิกซ์มากขึ้นด้วย piping ในตัวชื่อ 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สำหรับอย่างอื่นTrue1


% 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
  Fi

  ถ้า [! -f $ f2_sorted]; แล้วก็
    แมว $ 2 | จัดเรียง | 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
  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
  Fi

}


สคริปต์นี้ควรเริ่มด้วย#!/bin/bashหรือ
Alex

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.