2012-01-03 17 views
5

chcę analizować ciągi podobne do następujących do oddzielnych zmiennych za pomocą wyrażeń regularnych z poziomu Bash:Opcjonalne parametry w bash wyrażenia regularnego

Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";attributes="occi.core.id occi.core.title"; 

lub

Category: resource;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Resource";rel="http://schemas.ogf.org/occi/core#entity";attributes="occi.core.summary"; 

Pierwsza część przed „tytuł” jest wspólny dla wszystkich łańcuchów, tytuł części i atrybuty są opcjonalne.

Udało mi się wyodrębnić obowiązkowe parametry wspólne dla wszystkich ciągów, ale mam problem z opcjonalnymi parametrami niekoniecznie występującymi we wszystkich ciągach. O ile się dowiedziałem, Bash nie obsługuje nieprzechwytujących nawiasów, których użyłbym w tym celu.

Oto co osiągnąłem do tej pory:

CATEGORY_REGEX='Category:\s*([^;]*);scheme="([^"]*)";class="([^"]*)";' 
category_string='Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";attributes="occi.core.id occi.core.title";' 
[[ $category_string =~ $CATEGORY_REGEX ]] 
echo ${BASH_REMATCH[0]} 
echo ${BASH_REMATCH[1]} 
echo ${BASH_REMATCH[2]} 
echo ${BASH_REMATCH[3]} 

Wyrażenie regularne chciałbym użyć (i który pracuje dla mnie w Ruby) byłoby:

CATEGORY_REGEX='Category:\s*([^;]*);\s*scheme="([^"]*)";\s*class="([^"]*)";\s*(?:title="([^"]*)";)?\s*(?:rel="([^"]*)";)?\s*(?:location="([^"]*)";)?\s*(?:attributes="([^"]*)";)?\s*(?:actions="([^"]*)";)?' 

Czy istnieje inne rozwiązanie do parsowania ciągu za pomocą narzędzi wiersza poleceń bez konieczności powrotu do perla, pythona czy ruby?

Odpowiedz

6

Nie sądzę, że w bash regex istnieją grupy przechwytujące, więc możesz użyć języka skryptowego lub usunąć ?: ze wszystkich grup (?:...) i po prostu uważaj na grupy, do których się odwołujesz, na przykład :

CATEGORY_REGEX='Category:\s*([^;]*);\s*scheme="([^"]*)";\s*class="([^"]*)";\s*(title="([^"]*)";)?\s*(rel="([^"]*)";)?\s*(location="([^"]*)";)?\s*(attributes="([^"]*)";)?\s*(actions="([^"]*)";)?' 
category_string='Category: entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="Entity";attributes="occi.core.id occi.core.title";' 
[[ $category_string =~ $CATEGORY_REGEX ]] 
echo "full:  ${BASH_REMATCH[0]}" 
echo "category: ${BASH_REMATCH[1]}" 
echo "scheme:  ${BASH_REMATCH[2]}" 
echo "class:  ${BASH_REMATCH[3]}" 
echo "title:  ${BASH_REMATCH[5]}" 
echo "rel:  ${BASH_REMATCH[7]}" 
echo "location: ${BASH_REMATCH[9]}" 
echo "attributes: ${BASH_REMATCH[11]}" 
echo "actions: ${BASH_REMATCH[13]}" 

Należy zauważyć, że rozpoczynając od opcjonalne parametry musimy pominąć grupę każdym razem, ponieważ parzyste grupy te z 4 na zawierać nazwę parametru, jak i wartości (jeśli parametr jest obecna).

+0

To naprawdę działa. To nie jest najbardziej eleganckie rozwiązanie, ale dopóki w bashie nie ma grup przechwytujących, obejście polegające na pomijaniu grupy za każdym razem jest prawdopodobnie najlepszym rozwiązaniem. Jedna rzecz wciąż mnie niepokoi: jeśli za dowolnym średnikiem są spacje, wyrażenie regularne nie działa, tak więc za nimi są "\ s *" wzorce pasujące do białych znaków. –

+0

Wygląda na to, że znaki specjalne, takie jak "\ s *", nie działają. Zastąpienie go tylko spacją działało jednak: "\ s *" => "*" –

+0

Spróbuj użyć [[: spacja:]] * zamiast \ s. –

0

Można emulować niedopasowanych grup w bash używając trochę magii wyrażeń regularnych:

   _2__ _4__ _5__ 
[[ "[email protected]" =~ ((.+)@|)((.+)/|)(.+) ]]; 
echo "${BASH_REMATCH[2]:--} ${BASH_REMATCH[4]:--} ${BASH_REMATCH[5]:--}" 
# Output: fu - k 

Postacie @ i / są częścią łańcucha możemy zanalizować. Rura Regexp | służy do dopasowania lewej lub prawej (pustej) części.

Dla ciekawych, ${VAR:-<default value>} jest zmiennym rozszerzeniem o wartości domyślnej w przypadku, gdy $ VAR jest pusty.

+0

To nie działa dla mnie. Po prostu otrzymuję trzy kreski. – Joeytje50