2012-01-03 17 views
5

que quiero analizar cadenas similares a los siguientes en variables separadas usando expresiones regulares dentro de Bash:parámetros opcionales en Bash expresión regular

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

o

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"; 

La primera parte antes de "título" es común a todas las cadenas, el título y los atributos de las partes son opcionales.

Logré extraer los parámetros obligatorios comunes a todas las cadenas, pero tengo problemas con los parámetros opcionales no necesariamente presentes para todas las cadenas. Por lo que descubrí, Bash no es compatible con paréntesis de no captura que usaría para este propósito.

Aquí es lo que he logrado hasta el momento:

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]} 

La expresión regular me gustaría utilizar (y que está trabajando para mí en Ruby) sería:

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

¿Hay alguna otra solución para analizar la cadena con herramientas de línea de comandos sin tener que recurrir a perl, python o ruby?

Respuesta

6

No creo que la captura no existen grupos de expresiones regulares en bash, por lo que sus opciones son utilizar un lenguaje de programación o para quitar el ?: de todos los grupos y (?:...) sólo tenga cuidado acerca de qué grupos se hace referencia, por ejemplo, :

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]}" 

Nota que a partir de los parámetros opcionales que necesitamos para omitir un grupo cada vez, debido a que los grupos de número par de 4 en contienen el nombre del parámetro, así como el valor (si el parámetro está presente).

+0

Eso de hecho está funcionando. No es la solución más elegante, pero siempre que no haya grupos no capturadores en bash, la solución alternativa de saltear un grupo cada vez es probablemente la mejor solución. Una cosa todavía me molesta: si hay espacios detrás de cualquier punto y coma, la expresión regular falla incluso así hay patrones "\ s *" detrás de ellos para que coincida con espacios en blanco. –

+0

Parece que los caracteres especiales como "\ s *" no funcionan. Sustituirlo con solo un espacio funcionó: "\ s *" => "*" –

+0

Intenta usar [[: espacio:]] * en lugar de \ s. –

0

puede emular grupos no coincidentes en bash utilizando un poco de la magia de expresiones regulares:

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

Caracteres @ y / son partes de la cadena que analizar. La tubería Regexp | se utiliza para la coincidencia de partes izquierda o derecha (vacía).

Por curiosidad, ${VAR:-<default value>} es una expansión variable con valor predeterminado en caso de que $ VAR esté vacío.

+0

Esto no funciona para mí. Simplemente recibo tres guiones. – Joeytje50

Cuestiones relacionadas