Jak pobrać listę pozycji pomiędzy dwoma frazami?

0

Witajcie,

Mam pewien plik tekstowy, który zawiera dwie kluczowe klauzule nazwijmy ją na potrzeby przykładu "begin" oraz "end". Znajdują się one mniej więcej po środku pliku i może to wyglądać mniej więcej tak:

 ...
 begin
   xxx,
   yyy,
   zzz;
 
 end
 ...

mogą też być puste linie między xxx...zzz czyli tak:

 ...
 begin
   xxx,

 
   yyy,
   zzz;
 
 end
 ...

Potrzebowałbym teraz jakoś sprytnie odczytać ten plik tekstowy wyszukując begin oraz end odczytać wszystko co jest między tymi frazami i wrzucić to do listy lub seta typu {xxx,yyy,zzz}.

Udało mi się to zrobić bo ostatni element zawsze ma ; na końcu, a wcześniejsze zakończone są, ale robię to w bardzo oldschoolowy sposób czyli wyszukuję pozycji begin, potem end odczytuję wszystko pomiędzy i parsuję na podstawie przecinków i ;.

Kod jest duży i brzydki natomiast liczę na pomoc bardziej zaawansowanych użytkowników, którzy podpowiedzą mi jak to zrobić bardziej elegancko np używając map lub lambdy, a kto wie może już jest jakieś gotowe narzędzie, które mi to ogarnie? Podpowiecie coś?

46

regex?

2

Daj jakiś swój przykładowy kod albo zerknij czy to działa:

from io import open

file = open("plik.txt", "r")
text = file.read()
file.close()

begin_index = text.find("begin")
end_index = text.find("end")

target_text = text[begin_index + 5:end_index]

target_list = target_text.split(",")
target_set = set(target_list)

print(target_list)
print(target_set)
3

Ok, ale na podanym przykładzie masz pokazane, że każda informacja jest w osobnej linii - dlatego nie rozumiem fragmentu parsuję na podstawie przecinków i ;.

Pythona za bardzo nie znam, ale na szybko znalazłem, że jest takie coś jak readline - https://www.w3schools.com/python/ref_file_readline.asp:

The readline() method returns one line from the file.

I teraz lecimy, może mało wyrafinowaną, ale skuteczną metodą:

  1. wczytujesz pliki linia po linii
  2. jeśli wczytana linia posiada begin to znaczy, że rozpoczynamy dodawanie do listy
  3. robisz kolejnego readline, jeśli linia pusta to nic się nie dzieje
  4. jeśli nie jest pusta - usuwasz z końca średniki czy przecinki (jeśli ma być kolekcja bez nich)
  5. jeśli po usunięciu przecinka masz end to znaczy, że kończymy zabawę
  6. jeśli nie było end, ale doszliśmy do końca pliku - także kończymy zabawę

Powiedz proszę - w czym jest problem. Bo zadanie wydaje się dość trywialne i zastanawiam się, co jest tutaj haczykiem/co chcesz zmienić. podpowiedzą mi jak to zrobić bardziej elegancko np używając map lub lambdy, a kto wie może już jest jakieś gotowe narzędzie, które mi to ogarnie? Podpowiecie coś? - tylko pytanie: po co? Czy chodzi o to, żeby wyglądało bardziej PRO? Nie sądzę, żeby była różnica w wydajności, bo najwolniejszym fragmentem całości będzie odczyt z pliku - a te dane, niezależnie od sposobu ich przetwarzania, i tak będziesz misiał wczytać.

2

@cerrato:

cerrato napisał(a):

Powiedz proszę - w czym jest problem. Bo zadanie wydaje się dość trywialne i zastanawiam się, co jest tutaj haczykiem/co chcesz zmienić.

Zgadzam się że niejasności dużo.
Ścieżki są różne
a) tak jak @woolfik otagował: parser. Ja osobiście, jak plik jest ważny, rozwojowy (w syntaxie / obsłudze błędów) i do długofalowego życia, nie mam hamulca napisania parsera (w innych językach - C++, Java , C#). Wieksozść z nich ma przynajmniej kilkanaście lat szczęśliwej eksploatacji (w tym wzbogacania pliku)

b) tu jest wyrażna struktura liniowa. Zgromadzić linię pomiędzy begin /end w kolejce / liscie jak pisze @cerrato . w DRUGIM przebiegu procesować wg zawartości linii - metodą naiwną, tj nie specjalizowanym parserem. Nie wiem, w czym problem

3

To może inaczej ... jak robiłem kiedyś zadanie z AoC w pythonie to udało mi się to zrealizować kilkoma pętlami if;ami it a na redicie gość wrzucił rozwiązanie z lambdą i map co zajęło mu 1 linijkę kodu :) stąd moja prośbą. Dorzucę wam zaraz moje rozwiązanie i może w ten sposób podpowiecie coś więcej

OK, ale czy to Twoje szukanie jednolinijkowca ma jakieś uzasadnienie, czy po prostu taka zachcianka/ciekawość? Bo da się to pewnie zrobić krótko i zwięźle - ale po co? Dla zabawy/własnej satysfakcji/w ramach edukacji to spoko. Ale nie sądzę, żeby takie rozwiązanie miało wpływ na szybkość wykonania, a jeśli będzie miało, to obawiam się, że negatywny - bo zawsze jakieś duże mechanizmy (typ regex'y), które mogą robić 1000 rzeczy, z racji swojego skomplikowania mają narzut. A do tego są duże szanse, że kod w stylu tego, co tworzy @_13th_Dragon będzie zwyczajnie nieczytelny.

Czyli - podsumowując:

  • nie zyskujesz nic na prędkości działania (albo ją pogarszasz)
  • niszczysz czytelność kodu - na pierwszy rzut oka nikt nie będzie wiedział co się dzieje, trzeba będzie się zastanwawiać
  • poświęcasz czas na naprawianie czegoś, co już masz i co działa :P
  • oszczędzasz parę linijek na ekranie, co nie ma sensu, bo za miejsce na wyświetlaczu się nie płaci, czyli w sumie - nie ma żadnej oszczędności ;)
0

Zrobiłem coś w ten deseń:

def check_dependencies(mods):
    my_dict2 = {'tutaj słownik interesujących mnie wpisów na zasadzie klucz: wartość
                '}
    for m in mods:
        s = folder_mapping.get(os.path.basename(m).upper())
        if not s:
            s = os.path.basename(m)
        path = m.replace('/', '\\')
        listSet = set()
        if os.path.exists(f'{jP}repo\\{path}\\{s}.dpk'):
            startAdding = False
            with open(f'{jP}repo\\{path}\\{s}.dpk', 'r') as filled:
                for line in filled.readlines():
                    if line.strip() == 'requires':
                        startAdding = True
                    elif line.strip() == 'contains':
                        continue
                    sLine = (re.sub(r"\W+", '', line.upper().strip()))
                    if (sLine in my_dict2) and startAdding:
                        listSet.add(my_dict2.get(sLine))
    return list(listSet)

To działa choć na moje oko dość topornie to wygląda

W parametrze do funkcji leci lista plików do przeszukania natomiast dla uproszczenia zapytałem o jeden plik. Ogólnie to muszę w wielu folderach przeszukać pliki z rozszerzeniem .dpk wyciągnąć listę zależnych plików z sekcji requires (wszystko pomiędzy begin end) i na końcu zwrócić listę tych elementów, które zawierają się w słowniku my_dict2. Powyższy kod działa ale zastanawiam się czy da się go jakoś uprościć

2
woolfik napisał(a):

To działa choć na moje oko dość topornie to wygląda

Nie tylko wygląda

cerrato napisał(a):
  • poświęcasz czas na naprawianie czegoś, co już masz i co działa :P

Jaka jest prawda @woolfik ?
masz i działa, jak wierzy @cerrato , czy szukasz soluszynów na pierwsze podejsćie ?

Bo np 'end' nie przerywa działania, czyli ten kod nie może działać zgodnie ze specyfikacją.
W ogóle wygląda, jakbyś przed chwilą popełnił.
Jakieś startAdding, owszem, tak ma być, tyle że co wynika z ustawienia tej zmiennej w True ?

woolfik napisał(a):

Mam pewien plik tekstowy,

A kod dotyczy jakiejś zbiorowości plików ... więc ... sorry, ma się ochotę na pytania jak do studenta

1 użytkowników online, w tym zalogowanych: 0, gości: 1