Nowe posty

xx Problem ze sterownikami. (5)
2024-04-13, 21:25:16
xx Instalacja xfce4 (2)
2024-04-13, 16:20:17
xx Serie kompilacji bez instalacji dla “emerge” w Gentoo (2)
2024-04-08, 18:40:04
xx Plasma 6 w Neonie ssie trochę mniej ... (17)
2024-04-05, 10:03:46
xx Problem z Linux Lite po instalacji (3)
2024-04-03, 14:23:40
xx Jak właczyć num locka przy starcie systemu debian 12? (12)
2024-04-02, 17:43:54
xx Brak dźwieku w systemie. (5)
2024-04-02, 16:13:41
xx Dystrybucja pod HP Omen (7)
2024-03-29, 11:33:05
xx [Poradnik] Wyszukiwanie Sterowników (2)
2024-03-27, 21:08:23
xx Ile pingwinów? (1)
2024-03-27, 08:59:24

Autor Wątek: Bash: regexp nie zawierający słowa  (Przeczytany 6587 razy)

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Bash: regexp nie zawierający słowa
« dnia: 2009-02-09, 16:46:04 »
Witam.


Wie ktoś może jak w Bashu uzyskać wyrażenie regularne, które dopasuje się do wyrażenia, które nie zawiera danego słowa?


Chodzi o coś takiego:

W tekście "aaa11bbb22ccc22"
ma znaleźć "11" + dowolny ciąg znaków, ale nie słowo "22" + "22".
Czyli "11bbb22".

Wpisanie wyrażenia "11.*22" spowoduje dopasowanie za dużej części ciągu, bo "11bbb22ccc22".
Zamiast .* musi być coś, co dopasuje dowolne znaki poza słowem "22".


Składnia, jakiej używam:
$regexp=".........."
if [[ "$tekst" =~ $regexp ]]; then
  echo "$BASH_REMATCH[1]"
fi


Z góry dzięki.

arctgx

  • Gość
Bash: regexp nie zawierający słowa
« Odpowiedź #1 dnia: 2009-02-09, 19:02:16 »
#!/bin/bash
regexp="11(([^2]*)(2[^2]))*22"
for tekst in aaa11b2b2b22ccc22 aaa112b2b2b22ccc22
do
if [[ "$tekst" =~ $regexp ]]; then
echo tak
i=0;
n=${#BASH_REMATCH[*]}
echo $n
while [[ $i -lt $n ]]
do
echo $i "${BASH_REMATCH[i]}"
let i++
done
fi
done
Nie wiem czy dobrze wyłapałem: po jedenastce następny znak może nie być dwójką i występować dowolną ilość razy (również zero razy). Potem nie ma wyjścia jak natrafić na dwójkę (lub koniec dopasowywanego tekstu). My chcemy, aby na razie po niej nie było następnej dwójki. Taki ciąg nie-dwójek z następującą dwójką i nie-dwójką ;) może występować dowolną ilość razy i nie potrafię dopatrzyć się sytuacji, gdzie mógłby zawrzeć nie cytowane "22".

tak
4
0 11b2b2b22
1 2b
2
3 2b
tak
4
0 112b2b2b22
1 2b
2
3 2b
Poszukiwany wynik kryje się jednak w ${BASH_REMATCH[0]}. Na razie nie potrafię sobie uporządkować, dlaczego kolejne z możliwych dopasowań są puste lub równe "2b".

chmooreck

  • Gość
Bash: regexp nie zawierający słowa
« Odpowiedź #2 dnia: 2009-02-09, 23:01:23 »
http://en.wikipedia.org/wiki/Regular_expression#Lazy_quantification
nie wiem, czy bash wspiera, ale myślę, że warto sprawdzić ;)

xavery

  • Gość
Bash: regexp nie zawierający słowa
« Odpowiedź #3 dnia: 2009-02-11, 13:52:28 »
Nie bardzo rozumiem sedna problemu ale może coś takiego pomoże:
echo aaa11bbb22ccc22 | grep -Po '11.+?22'

ra-v

  • Gość
Bash: regexp nie zawierający słowa
« Odpowiedź #4 dnia: 2009-02-11, 16:39:41 »
mozna uzyć

wartosc=`echo "$tekst" | grep -vo "wyrażenie"`

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Bash: regexp nie zawierający słowa
« Odpowiedź #5 dnia: 2009-02-11, 17:49:45 »
@arctgx
Dokładnie tak robię. Ale takie coś odpada przy słowie mającym np. 20 znaków.

@chmooreck
Niestety, z tego co przetestowałem, =~ tego nie obsługuje, grep standardowo również nie.

@xavery
grep: Support for the -P option is not compiled into this --disable-perl-regexp binary
:|
Nie bardzo chce mi się to rekompilować. Poza tym skoro ja mam problem, to ktoś inny używając tego skryptu też może mieć.

arctgx

  • Gość
Bash: regexp nie zawierający słowa
« Odpowiedź #6 dnia: 2009-02-12, 16:43:31 »
Cytat: ultr
@arctgx
Dokładnie tak robię. Ale takie coś odpada przy słowie mającym np. 20 znaków.
Mógłbyś dać przykład słowa i wyrażenia, na którym ten pomysł zawodzi? Może zrozumiem ogólniejszy problem, a nie tylko ten jeden przykład.

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Bash: regexp nie zawierający słowa
« Odpowiedź #7 dnia: 2009-02-12, 18:13:18 »
Dokładnie chcę dopasowywać fragmenty kodu html.

Najprostszy przykład - dopasowanie wszystkiego między: < table...>______< /table>
Tyle, że pomiędzy tymi znacznikami nie może wystąpić inne < /table>, bo inaczej dopasuje mi pół dokumentu.

Więc muszę napisać:
< table...>(([^<]|<[^/]|< /[^t]|< /t[^a]|< /ta[^b]|< /tab[^l]|< /tabl[^e]|< /table[^>])*)< /table>
Z powyższego wyrażenia trzeba usunąć spacje. Musiałem je wstawić przy tagach, bo engine forum usuwał pół wtrażenia. A przy wstawieniu < /table> w otwartym tekście rozjeżdża się cała strona forum. Wypadało by poprawić ten błąd :)

arctgx

  • Gość
Bash: regexp nie zawierający słowa
« Odpowiedź #8 dnia: 2009-02-12, 18:53:28 »
No tak, to praktycznie ten sam sposób z dłuższym ogranicznikiem - a może, przy braku innych pomysłów, da się napisać funkcję, która sama wygeneruje taki paskudny warunek?

A ten sposób bierze się z tego, że nikt z nas nie zna sposobu na zanegowanie całego wyrażenia, więc negujemy znak po znaku...

Próbowałem zanegować całość z włączoną opcją extglob (czyli *(!(22)) ), ale albo czegoś nie dopatrzyłem, albo tych dopasowań nie można użyć w wyrażeniach regularnych, a tylko w nazwach plików lub zmiennych.

Offline ultr

  • Users
  • Guru
  • *****
  • Wiadomości: 1177
    • Zobacz profil
Bash: regexp nie zawierający słowa
« Odpowiedź #9 dnia: 2009-02-13, 13:12:24 »
Też pomyślałem o funkcji do generowania tego. Myślałem tylko, że da się jakoś ładniej.

Gdyby komuś było potrzebne:
NotRegexp()
{
word="$1"
if [ "${#word}" == 0 ]; then
echo "";
return;
fi
regexp="("
part=""
char="${word:0:1}"
regexp="${regexp}[^${char}]"
part="${char}"
for k in $( seq 1 `expr ${#word} - 1` ); do
char="${word:${k}:1}"
regexp="${regexp}|${part}[^${char}]"
part="${part}${char}"
done
regexp="${regexp})*"
echo "$regexp"
}
Użycie:
rx="innewarunki$( NotRegexp "slowo" )innewarunki"