staging.inyokaproject.org

Dateien vergleichen, diff, Ziel: "stimmen ersten 5 Zeichen - dann behalten"

Status: Ungelöst | Ubuntu-Version: Kubuntu 22.04 (Jammy Jellyfish)
Antworten |

dafosy

Anmeldungsdatum:
26. Februar 2012

Beiträge: 164

Hallo Community,

ich habe folgende Aufgabe:

(1) Vergleiche 2 Text-Dateien A.txt + B.txt miteinander.

(2) Erzeuge eine Datei C.txt, welche alle Zeilen enthält, die in B.txt vorkommen und die ersten 5 Zeichen dieser Zeile ebenfalls auch in A.txt vorkommen.

(3) Erzeuge eine Datei D.txt, welche A.txt (minus) die aus (2) vorhandenen Zeilen enthält.

Bsp. A.txt:

1.2.3.4.5.6.7.8.9
2.2.3.4.5.6.7.8.9
3.2.3.4.5.6.7.8.9
4.2.3.4.5.6.7.8.9
5.2.3.4.5.6.7.8.9
6.2.3.4.5.6.7.8.9
7.2.3.4.5.6.7.8.9
8.2.3.4.5.6.7.8.9

Bsp. B.txt:

1.2.3.4.5.6.7.8.9
2.2.3.4.5.6.7.8.9
3.2.3.A.B.C.D.E.F
4.2.3.4.5.6.7.8.9
5.2.3.4.5.6.7.8.9
6.2.3.A.B.C.D.E.F
7.2.3.A.B.C.D.E.F
8.2.3.4.5.6.7.8.9

Bsp. C.txt

3.2.3.A.B.C.D.E.F
6.2.3.A.B.C.D.E.F
7.2.3.A.B.C.D.E.F

Bsp. D.txt

1.2.3.4.5.6.7.8.9
2.2.3.4.5.6.7.8.9
4.2.3.4.5.6.7.8.9
5.2.3.4.5.6.7.8.9
8.2.3.4.5.6.7.8.9

Jemand eine Idee?

Einen hilfreichen Tip begrüße ich. dafosy

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

dafosy schrieb:

ich habe folgende Aufgabe:

(1) Vergleiche 2 Text-Dateien A.txt + B.txt miteinander.

(2) Erzeuge eine Datei C.txt, welche alle Zeilen enthält, die in B.txt vorkommen und die ersten 5 Zeichen dieser Zeile ebenfalls auch in A.txt vorkommen.

(3) Erzeuge eine Datei D.txt, welche A.txt (minus) die aus (2) vorhandenen Zeilen enthält.

Was ist denn das? Das sieht sehr nach einer Hausaufgabe aus.

Jemand eine Idee?

awk oder Ruby

shiro Team-Icon

Supporter

Anmeldungsdatum:
20. Juli 2020

Beiträge: 1303

Hallo dafosy,

(1) Vergleiche 2 Text-Dateien A.txt + B.txt miteinander.

Ja, und was willst du dabei heraus bekommen? Was soll denn verglichen werden?

(2) Erzeuge eine Datei C.txt, welche alle Zeilen enthält, die in B.txt vorkommen und die ersten 5 Zeichen dieser Zeile ebenfalls auch in A.txt vorkommen.

Bist du sicher, dass deine Bedingung (2) korrekt formuliert ist? So wie ich sie verstehe, kommt das Beispiel von C.txt nicht heraus.

Wenn ich deine Aufgabenstellung (so wie ich sie verstehe) umsetzte, erhalte ich folgendes Ergebnis für C.txt:

$ cut -b1-5 A.txt | grep -f - B.txt
1.2.3.4.5.6.7.8.9
2.2.3.4.5.6.7.8.9
3.2.3.A.B.C.D.E.F
4.2.3.4.5.6.7.8.9
5.2.3.4.5.6.7.8.9
6.2.3.A.B.C.D.E.F
7.2.3.A.B.C.D.E.F
8.2.3.4.5.6.7.8.9
$ 

Damit du C.txt erhältst, habe ich mal folgenden Befehl verwendet, der aber nicht deiner Anforderung entspricht:

$ join -t, -v2 -j1 A.txt B.txt
3.2.3.A.B.C.D.E.F
6.2.3.A.B.C.D.E.F
7.2.3.A.B.C.D.E.F
$ 

Überprüfe bitte die Aufgabenstellung von (2).

(3) Erzeuge eine Datei D.txt, welche A.txt (minus) die aus (2) vorhandenen Zeilen enthält.

Ok, das ist ein einfaches "grep":

$ cut -b1-5 C.txt | grep -v -f - A.txt
1.2.3.4.5.6.7.8.9
2.2.3.4.5.6.7.8.9
4.2.3.4.5.6.7.8.9
5.2.3.4.5.6.7.8.9
8.2.3.4.5.6.7.8.9
$ 

awk oder Ruby

Klar, das geht natürlich auch.

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

welche Angabe auch fehlt: zeilenweise vergleichen, d.h. 1. Zeile mit 1. Zeile, 2. mit 2. usw.? Oder beliebig mit beliebig, d.h. es soll auch geprüft werden, ob die Bedinung z.B. auf die 3. Zeile von A und die 8. Zeile von B zutrifft?

awk oder Ruby

Klar, das geht natürlich auch.

Oder Python oder Go oder Java oder ... Im Prinzip geht das mit allem, was Dateien lesen und dann zeilenweise drüber iterieren kann.

Gruß, noisefloor

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11278

dafosy schrieb:

Jemand eine Idee?

Irgendeine Sprache mit Hashmaps - z.B. Python3:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3
import sys
from pathlib import Path
from difflib import unified_diff

file_1 = "A.txt"
file_2 = "B.txt"

a = {line[:5]: line for line in Path(file_1).read_text().splitlines()}
b = {line[:5]: line for line in Path(file_2).read_text().splitlines()}

# (1)
sys.stdout.writelines(unified_diff([f"{l}\n" for l in a.values()], [f"{l}\n" for l in b.values()], fromfile=file_1, tofile=file_2))
# (2)
c_lines = [line for begin, line in b.items() if begin in a]
Path('C.txt').write_text("\n".join(c_lines))
# (3)
Path('D.txt').write_text("\n".join((line for line in a.values() if line not in c_lines)))

PS: ist da nicht der Inhalt von C.txt und D.txt vertauscht?

dafosy

(Themenstarter)

Anmeldungsdatum:
26. Februar 2012

Beiträge: 164

@rklm: Hausaufgabe - geil!

Nee, ich komme tatsächlich von hier: https://forum.ubuntuusers.de/topic/vergleich-textdatei-und-dann-teile-aus-beiden-/

Mein Problem ist, dass ich eine sich dynamisch verändernde A.txt mit MAC-Adressen, IP-Adressen und Nicknames habe. In einer B.txt ordne ich MAC-Adressen Nicknames zu. Das Basis-Programm löscht in A.txt allerdings regelmäßig die Nicknames.

Plan ist nun also:

A.txt so zu kürzen, dass sie mit B.txt übereinstimmt - jede Zeile also gleich ist - zumindest die ersten x-Zeichen (MAC-Adressen). Dann läuft eine join-Routine drüber und ordnet die Nicknames zu. Danach plane ich die nicht zuordbaren Zeilen (also den Utnerschied von A.txt und B.txt) wieder hinzuzufügen und dann in das ursprüngliche Programm zurück zu spielen. Dann sehe ich nämlich die Nicknames.

Und das gerne mittels diff, sed, awk und Co. python ist mir zu aufwendig und da habe ich keinen Plan.

Grüße und nachher habe ich noch ein paar Minuten zum weiter probieren.

/dafosy

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13242

dafosy schrieb:

Mein Problem ist, dass ich eine sich dynamisch verändernde A.txt mit MAC-Adressen, IP-Adressen und Nicknames habe. In einer B.txt ordne ich MAC-Adressen Nicknames zu. Das Basis-Programm löscht in A.txt allerdings regelmäßig die Nicknames.

Plan ist nun also:

A.txt so zu kürzen, dass sie mit B.txt übereinstimmt - jede Zeile also gleich ist - zumindest die ersten x-Zeichen (MAC-Adressen). Dann läuft eine join-Routine drüber und ordnet die Nicknames zu. Danach plane ich die nicht zuordbaren Zeilen (also den Utnerschied von A.txt und B.txt) wieder hinzuzufügen und dann in das ursprüngliche Programm zurück zu spielen. Dann sehe ich nämlich die Nicknames.

Das ist doch mal eine gute Beschreibung der Anforderung. Im Prinzip geht es darum, A.txt mit den Informationen aus B.txt anzureichern. Das Format der Dateien sieht allerdings ziemlich künstlich aus. Ist das wirklich das tatsächliche Format? Und falls ja, wie erkennt man die Grenze zwischen MAC und Nick?

Grob würde ich das so machen (ungetestet und unter der Annahme, dass beide Dateien dasselbe Format haben):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/ruby

def parse(line)
  ["x", "y"] # [mac, nick]
end

# read mapping
map = {}

File.foreach(ARGV[0]) do |line|
  mac, nick = parse(line)
  map[mac] = nick
end

# transform
File.foreach(ARGV[1]) do |line|
  mac, nick = parse(line)
  nick = map[mac] || nick # mapping takes precedence!
  puts "#{mac} #{nick}"
end

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4735

Davon ausgehend, dass die Elemente in den Zeilen durch Leerzeichen getrennt sind, ein Python-Ansatz:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/env python3
from attr import attrib, attrs


@attrs
class Record:
    mac = attrib()
    ip = attrib()
    nickname = attrib(default=None)

    def __str__(self):
        values = [self.mac, self.ip]
        if self.nickname is not None:
            values.append(self.nickname)
        return " ".join(map(str, values)) + "\n"

    @classmethod
    def parse(cls, text):
        return cls(*text.split(maxsplit=2))


def main():
    with open("A.txt", encoding="utf-8") as lines:
        mac_to_record = {
            record.mac: record for record in map(Record.parse, lines)
        }

    with open("B.txt", encoding="utf-8") as lines:
        for mac, nickname in (line.partition(" ") for line in lines):
            mac_to_record[mac].nickname = nickname

    with open("result.txt", "w", encoding="utf-8") as file:
        file.writelines(map(str, mac_to_record.values()))


if __name__ == "__main__":
    main()
Antworten |