Nie jesteś zalogowany na forum.

#1 2015-10-21 12:23:21

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

regexp leniwy (z lewej i prawej strony)

Dla potrzeb mojego skryptu chcę wyciągnąć pewien ciąg znaków przy pomocy grep'a.
Mam poniższy ciąg znaków:

aaa---bbb---ccc---aaa---fff---zzz---ggg---zzz

Potrzebuję z tego uzyskać:
     

aaa---fff---zzz

a uzyskuję:
     

aaa---bbb---ccc---aaa---fff---zzz

Jak stworzyć poprawny zapis dla wyrażenia leniwego żeby i lewej i z prawej było to leniwe.
Na razie to umiem tylko z prawej strony uzyskać działanie leniwe.

grep aaa.*?zzz

Grep zaczyna od szukania aaa i wyszukuje najkrótszy ciąg znaków aż natrafi na zzz?
Wszystko fajnie ale po drodze znowu natrafia na aaa a to już dla mnie odpada.
Proszę o podpowiedź :)

Ostatnio edytowany przez addos (2015-10-21 12:24:02)


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#2 2015-10-21 15:35:09

e09ee49a
Użytkownik
Data rejestracji: 2015-09-06
Liczba postów: 5

Odp: regexp leniwy (z lewej i prawej strony)

Nie do końca wiem, co chcesz osiągnąć, ale jak umiesz to zrobić z prawej, to możesz obrócić ciąg przez rev, zrobić to i znowu obrócić. Nie będzie to optymalne ale powinno działać.

Ostatnio edytowany przez e09ee49a (2015-10-21 15:38:32)

Offline

#3 2015-10-22 10:00:55

dracorp
Użytkownik
Lokalizacja: Poland, Gdańsk
Data rejestracji: 2015-09-06
Liczba postów: 98
WWW

Odp: regexp leniwy (z lewej i prawej strony)

Nie wiem* czy to zadziała, żeby dopasować do środka. Na początku dopasowuje aaa, potem szuka .*?  - wybiera najmniej możliwie czyli nic i potem zzz. Nie pasuje wraca z powrotem do aaa i wydłuża wzorzec pasujący .*?. I pewnie dlatego dopasowuje od początku do pierwszego zzz.
Sam grep dziwnie działa, tak jakby w Perlu byłaby użyta flaga g (global match) we wzorcu.

* nie mówię że się nie da bo mogę się mylić, wyrażenia regularne ciągle mnie zaskakują.

Offline

#4 2015-10-22 11:44:34

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

Odp: regexp leniwy (z lewej i prawej strony)

To może z innej strony to ugryźć. Mam 2 pomysły.

1. Czy istnieje możliwość zapisu wyrażenia regularnego w stylu:

znajdź fragment tekstu w którym litera "a" wystąpi maksymalnie 4 razy (niekoniecznie ciągiem jedna za drugą)

Czyli fragment może zawierać dowolną ilość znaków, dowolnie pomieszanych bo kolejność nie jest istotna, ale warunek jest jeden: nie może tam wystąpić więcej liter "a" niż 4.
Czy wyrażenie regularne to umożliwia czy to już zabawa z wyższej półki?

2. Czy istnieje możliwość wyszukania ciągu znaków za pomocą jakiejś reguły, np. ".*" i do tego właśnie fragmentu dodać kolejny warunek.
Mamy takie coś jak alternatywę, np.   

KOT|kot

a mi potrzebny jest AND, np.   

.*? && nie jest to słowo KOT

A tak przy okazji: jak się neguje całe słowo ale nie zakres liter?

Ostatnio edytowany przez addos (2015-10-22 11:46:36)


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#5 2015-10-23 12:09:34

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

Odp: regexp leniwy (z lewej i prawej strony)

Może te przykłady nie trafiają do wyobraźni. Teraz przykład bardziej zrozumiały.

Mam w pliku taki ciąg danych: kolejno "domena1" "opis1" "domena2" "opis2" "domena3" "opis3" itd.

"http://www.domena1.pl/pliki/a1.html" "abcd/abcd" "http://domena2/files/a2.html" "jakiś/tekst/tmp" "http://www.domena3.pl/archiwum/a3.php" "ijkl/ijkl/ijkl" "http://domena4/dane/a4.html" "mnopq/test/test2"

Zaznaczam, że dane są w jednej linii a nie w osobnych bo wtedy wszystko mi działa OK.

Potrzebuję wyrażenie regularne, które wybierze tylko same adresy. Wynik chcę uzyskać taki:

http://www.domena1.pl/pliki/a1.html
http://www.domena2.pl/files/a2.html
http://www.domena4.pl/dane/a4.html

Jakiś pomysł?

Ostatnio edytowany przez addos (2015-10-23 12:11:32)


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#6 2015-10-23 13:34:42

dracorp
Użytkownik
Lokalizacja: Poland, Gdańsk
Data rejestracji: 2015-09-06
Liczba postów: 98
WWW

Odp: regexp leniwy (z lewej i prawej strony)

Do "negacji" to grep -v czyli

echo tekst | grep '.*?cos' | grep -v  kot

Dla grep możesz użyć opcji -P i używać Perlowych wyrażeń regularnych lub może lepiej od razu go użyć? Plus kupa innych narzędzi.

echo 'a---bbb---ccc---aaa---fff---zzz---ggg---zzz' | perl -ne 'print if @{[ m/a/g ]} == 4'

W Perlu jak szukasz coś w tekście (m//) i użyjesz opcji g to zwróci ci listę wszystkich wystąpień i potem można to porównać z ilością wystąpień.

Offline

#7 2015-10-23 14:12:35

e09ee49a
Użytkownik
Data rejestracji: 2015-09-06
Liczba postów: 5

Odp: regexp leniwy (z lewej i prawej strony)

Jeśli w opisach nie występuje "http://", to zawsze możesz szukać słów, które się zaczynają od takiego wzorca aż do cudzysłowu.

grep -o \http\:\/\/[^\"]*

EDIT:
Jeśli ciąg zawsze ma postać "adres opis adres opis...", to można wypisać co drugie słowo i nie bawić się w wyrażenia regularne

awk '{for(i=1;i<=NF;i+=2){print substr($i, 2, length($i)-2)}}'

Ostatnio edytowany przez e09ee49a (2015-10-23 14:20:35)

Offline

#8 2015-10-23 14:17:24

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

Odp: regexp leniwy (z lewej i prawej strony)

Opcję -v znam i często jej używam.
Niestety gdy te dane sa zapisane w jednej linii to ta opcja zaneguje mi całą linię, a mi nie o to chodzi :)

W skrócie mówiąc:
1. plik może zawierać linie gdzie dana fraza wystąpi 1 raz i wtedy opcja -v jak najbardziej zadziała
2. plik może zawierać linie gdzie dana fraza wystąpi równocześnie z niechcianą frazą i wtedy opcja -v zaneguje całą linię, a to błąd
3. chcę uzyskać wszystkie frazy zaczynające się od słowa "http" a kończące się jakimś rozszerzeniem, np "html", "php" itp. ale nawet gdy takie frazy wystąpią więcej niż 1 raz w jednej linii

Tutaj przykład. Ciekawi mnie jak ma wyglądać regexp żeby to uzyskać?

"http://www.domena1.pl/pliki/a1.html" "abcd/abcd" "http://domena2/files/a2.html" "jakiś/tekst/tmp" "http://www.domena3.pl/archiwum/a3.php" "ijkl/ijkl/ijkl" "http://domena4/dane/a4.html" "mnopq/test/test2"

Ewentualnie jeszcze prościej - mamy plik o nazwie plik_testowy.txt z taką zawartością:

www.domena1.pl/a1.html     AAAA      www.domena1.pl/a2.html      AAAA      www.domena1.pl/a3.html      AAAA      www.domena1.pl/a4.html      AAAA

Jak zastosować tu regexp, żeby uzyskać same URL ?
W teorii poniższe polecenie powinno dać to czego chcę ale tak nie jest, i nie wiem czemu:

grep -Eo "www.*?\.html" plik_testowy.txt

Ostatnio edytowany przez addos (2015-10-23 14:23:25)


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#9 2015-10-23 14:29:26

e09ee49a
Użytkownik
Data rejestracji: 2015-09-06
Liczba postów: 5

Odp: regexp leniwy (z lewej i prawej strony)

Wg. googli zwykły grep nie wspiera leniwych wyrażeń "*?", więc wyświetla ci wynik od pierwszego "www" od ostatniego ".html". Użyj

grep -Po "www.*?\.html" plik_testowy.txt

.

Offline

#10 2015-10-23 14:29:58

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

Odp: regexp leniwy (z lewej i prawej strony)

e09ee49a napisał/a:

Jeśli w opisach nie występuje "http://", to zawsze możesz szukać słów, które się zaczynają od takiego wzorca aż do cudzysłowu.

grep -o \http\:\/\/[^\"]*

No właśnie tak robię i ten cudzysłów jest znajdowany nie pierwszy tylko ostatni, a po drodze są inne fragmenty, które są traktowane jako część adresu, a w rzeczywistości są to inne adresy.

EDIT:
Jeśli ciąg zawsze ma postać "adres opis adres opis...", to można wypisać co drugie słowo i nie bawić się w wyrażenia regularne

awk '{for(i=1;i<=NF;i+=2){print substr($i, 2, length($i)-2)}}'

Tu może podałem prosty przykład ale plik zawiera dużo bardziej skomplikowane dane i nie jest to oparte na prostym przypisaniu, że w kolumnie 1-3 mam adresy, a w kolumnach 4-8 opis, itd.

awk znam i jak najbardziej często tak sobie coś wycinam
Można też to zrobić przy pomocy cut, sed ale wszystko mi działa gdy mam wszystko w osobnych liniach.
Jeżeli mam kilka adresów w jednej linii to już się to sypie.

Spróbuj podany przez mnie ostatni przykład z plikiem testowym i daj znać jeżeli uda ci się to :)


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#11 2015-10-23 14:39:48

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

Odp: regexp leniwy (z lewej i prawej strony)

e09ee49a napisał/a:

Wg. googli zwykły grep nie wspiera leniwych wyrażeń "*?", więc wyświetla ci wynik od pierwszego "www" od ostatniego ".html". Użyj

grep -Po "www.*?\.html" plik_testowy.txt

.

Dzięki... częściowo działa :)
Częściowo bo przy lekko innej formie pliku znowu się gubi.... tutaj przykład:
-- zamiast tego (tu działa OK):

www.domena1.pl/a1.html     AAAA      www.domena1.pl/a2.html      AAAA      www.domena1.pl/a3.html      AAAA      www.domena1.pl/a4.html      AAAA
www.domena1.pl/a1.html
www.domena1.pl/a2.html
www.domena1.pl/a3.html
www.domena1.pl/a4.html

--zmień na to (tu znowu źle):

www.domena1.pl/a1.html     AAAA      www.domena1.pl/a2.html      AAAA      www.domena1.pl/a3.php      AAAA      www.domena1.pl/a4.html      AAAA
www.domena1.pl/a1.html
www.domena1.pl/a2.html
www.domena1.pl/a3.php      AAAA      www.domena1.pl/a4.html

Ostatnio edytowany przez addos (2015-10-23 14:49:53)


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#12 2015-10-23 14:53:05

e09ee49a
Użytkownik
Data rejestracji: 2015-09-06
Liczba postów: 5

Odp: regexp leniwy (z lewej i prawej strony)

Jak nie chcesz wyrażeń perla, to można zamiast * dać wszystko co nie jest spacją [^ ].
Albo można wypisać wszystkie rozszerzenia

grep -Eo "www\.[^ ]*\.(php|html)" test.txt

albo całkiem je pominąć i szukać do najbliższej spacji

grep -Eo "www\.[^ ]*" test.txt

.

Offline

#13 2015-10-23 15:13:40

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

Odp: regexp leniwy (z lewej i prawej strony)

Ale czemu zakładasz, że w nazwie pliku nie może wystąpić spacja? Niektóre z plików, które mam do przerobienia posiadają spację i wtedy lipa :(


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#14 2015-10-23 15:29:49

e09ee49a
Użytkownik
Data rejestracji: 2015-09-06
Liczba postów: 5

Odp: regexp leniwy (z lewej i prawej strony)

Myślałem, że to adresy stron, a nie nazwy plików. Nie spotkałem się jeszcze żeby była jawnie spacja, ewentualnie zakodowana jako "%20". Jest coś charakterystycznego, co kończy ścieżkę? Bo jeśli w ścieżce mogą być spacje i separatorem pól też jest spacja to nie mam pomysłu jak to sensownie zrobić.

Offline

#15 2015-10-23 16:23:36

addos
Użytkownik
Data rejestracji: 2015-09-01
Liczba postów: 142

Odp: regexp leniwy (z lewej i prawej strony)

Sprawdzam i ciekawostka: źródło strony pokazuje linki z "%20", a juz plik na dyski po zapisaniu ma spacje. Mimo wszystko wolę coś uniwersalnego niż dopasowane jednorazowo.


Info przy ew. problemach: Arch Linux x64, Plasma 5 (aktualna), CPU C2D E8400 (3GHz, 6MB cache), ASUS P5Q-PRO (BIOS, bez UEFI), RAM 8GB (DDR2, Dual), GPU GF 9600GT (PCI-E, 512MB), SSD 250GB MLC (GPT, discard, Grub 2, all ext4), HDD 1TB (7200, SATA, AHCI, NCQ, MBR, all ext4), monitor 1920x1080@60Hz DVI, audio: ASUS Xonar DX (PCI-E x1, 5.1 analog, ALSA bez PulseAudio), klaw. PS/2, mysz USB

Offline

#16 2017-11-04 23:18:13

piomiq
Użytkownik
Lokalizacja: Warszawa
Data rejestracji: 2017-11-03
Liczba postów: 5
WWW

Odp: regexp leniwy (z lewej i prawej strony)

addos napisał/a:

Może te przykłady nie trafiają do wyobraźni. Teraz przykład bardziej zrozumiały.

Mam w pliku taki ciąg danych: kolejno "domena1" "opis1" "domena2" "opis2" "domena3" "opis3" itd.

"http://www.domena1.pl/pliki/a1.html" "abcd/abcd" "http://domena2/files/a2.html" "jakiś/tekst/tmp" "http://www.domena3.pl/archiwum/a3.php" "ijkl/ijkl/ijkl" "http://domena4/dane/a4.html" "mnopq/test/test2"

Zaznaczam, że dane są w jednej linii a nie w osobnych bo wtedy wszystko mi działa OK.

Potrzebuję wyrażenie regularne, które wybierze tylko same adresy. Wynik chcę uzyskać taki:

http://www.domena1.pl/pliki/a1.html
http://www.domena2.pl/files/a2.html
http://www.domena4.pl/dane/a4.html

Jakiś pomysł?

Może trochę późno podaję przykład rozwiązania i już sobie poradziłeś z tym, ale  powyższy problem rozwiązałbym w bardzo prosty, poniższy sposób:

cat plik.txt | tr ' ' '\n' | grep ^http

Założyłem tu, że w URL-ach i ciągach pomiędzy nimi nie ma spacji (tak jak w przykładzie). Spacje tylko rozdzielają te opakowane w cudzysłowy ciągi, które oczywiście znajdują się w jednej linii.


Intel® Core™ i7-6700 @ 3.40GHz (SkyLake) + 16GB ram + ASUS Xonar DX
Działa na nim: Linux 4.13.11-1-ARCH, Plasma 5.11.2 + KF-5.39 + Qt-5.9.2

Offline

Stopka

Napędzają nas PacmanVPS i MegiTeam

Forum oparte na FluxBB