2009-09-18 29 views
12

Considere las siguientes cadenas:¿Cómo puedo extraer subcadenas de una cadena en Perl?

1) Esquema ID: abc-456-hu5t10 (alta prioridad) *****

2) Esquema ID: frt-78F-hj542w (Balanced)

3) Esquema ID: 23f-f974-nm54w (súper fórmula ejecución) *****

y así sucesivamente en el formato anterior: las partes en negrita son cambios en las cadenas.

==>Imagine que tengo muchas cadenas de formato Mostradas arriba. Quiero elegir 3 subcadenas (como se muestra en negrita a continuación) de cada una de las cadenas anteriores.

  • primera subcadena que contiene el valor alfanumérico (en, por ejemplo por encima de ella es "abc-456-hu5t10")
  • segunda subserie que contiene la palabra (en el ejemplo anterior es "alta prioridad")
  • tercera subcadena que contiene * (* IF está presente al final de la cadena ELSE dejarlo)

¿Cómo elegir estos 3 subseries de cada cadena se muestra arriba? Sé que se puede hacer usando expresiones regulares en Perl ... ¿Pueden ayudarme con esto?

+0

¿Puede la cadena entre paréntesis anidados contiene en sí mismo? –

Respuesta

29

se podría hacer algo como esto:

my $data = <<END; 
1) Scheme ID: abc-456-hu5t10 (High priority) * 
2) Scheme ID: frt-78f-hj542w (Balanced) 
3) Scheme ID: 23f-f974-nm54w (super formula run) * 
END 

foreach (split(/\n/,$data)) { 
    $_ =~ /Scheme ID: ([a-z0-9-]+)\s+\(([^)]+)\)\s*(\*)?/ || next; 
    my ($id,$word,$star) = ($1,$2,$3); 
    print "$id $word $star\n"; 
} 

La clave es la expresión regular:

Scheme ID: ([a-z0-9-]+)\s+\(([^)]+)\)\s*(\*)? 

que descompone de la siguiente manera.

la cadena "ID Esquema:": fijo

Scheme ID: 

seguido de uno o más de los caracteres a-z, 0-9 o -. Utilizamos los soportes para capturarlo como $ 1:

([a-z0-9-]+) 

seguido de uno o más caracteres de espacio en blanco:

\s+ 

seguido de un corchete de apertura (que escapamos) seguido de cualquier número de caracteres que aren No es un corchete cercano, y luego un corchete de cierre (escapado). Utilizamos soportes sin escape para capturar las palabras como $ 2:

\(([^)]+)\) 

Seguido de algunos espacios cualquier quizá a *, capturados como $ 3:

\s*(\*)? 
2
(\S*)\s*\((.*?)\)\s*(\*?) 


(\S*) picks up anything which is NOT whitespace 
\s*  0 or more whitespace characters 
\(  a literal open parenthesis 
(.*?) anything, non-greedy so stops on first occurrence of... 
\)  a literal close parenthesis 
\s*  0 or more whitespace characters 
(\*?) 0 or 1 occurances of literal * 
+0

\ (([^)]) \) sería mejor que \ ((. *?) \), Ya que se garantiza que se detendrá en el primero. Los cuantificadores no codiciosos pueden causar retrocesos pesados, lo que mata el rendimiento. (Es poco probable, en este caso, admitirlo, pero evitarlos cuando no son necesarios sigue siendo un buen hábito para cultivar). La clase de personaje negada es también una declaración más clara de tu intención: estás buscando "cualquier cantidad de no-) caracteres ", no" el número más pequeño de ningún carácter, seguido de a), lo que hace que la expresión sea una coincidencia completa ". –

3

Se podría utilizar una expresión regular como los siguientes:

/([-a-z0-9]+)\s*\((.*?)\)\s*(\*)?/ 

Así, por ejemplo:

$s = "abc-456-hu5t10 (High priority) *"; 
$s =~ /([-a-z0-9]+)\s*\((.*?)\)\s*(\*)?/; 
print "$1\n$2\n$3\n"; 

impresiones

abc-456-hu5t10 
High priority 
* 
1

Hace tiempo que no Perl

while(<STDIN>) { 
    next unless /:\s*(\S+)\s+\(([^\)]+)\)\s*(\*?)/; 
    print "|$1|$2|$3|\n"; 
} 
0

Cadena 1:

$input =~ /'^\S+'/; 
$s1 = $&; 

Cadena 2:

$input =~ /\(.*\)/; 
$s2 = $&; 

Cadena 3:

$input =~ /\*?$/; 
$s3 = $&; 
1

Bueno, un chiste aquí:

perl -lne 'm|Scheme ID:\s+(.*?)\s+\((.*?)\)\s?(\*)?|g&&print "$1:$2:$3"' file.txt 

Ampliado a un simple script para explicar las cosas un poco mejor:

#!/usr/bin/perl -ln    

#-w : warnings     
#-l : print newline after every print        
#-n : apply script body to stdin or files listed at commandline, dont print $_   

use strict; #always do this.  

my $regex = qr{ # precompile regex         
    Scheme\ ID:  # to match beginning of line.      
    \s+    # 1 or more whitespace        
    (.*?)   # Non greedy match of all characters up to   
    \s+    # 1 or more whitespace        
    \(    # parenthesis literal        
    (.*?)   # non-greedy match to the next      
    \)    # closing literal parenthesis      
    \s*    # 0 or more whitespace (trailing * is optional)  
    (\*)?   # 0 or 1 literal *s         
}x; #x switch allows whitespace in regex to allow documentation. 

#values trapped in $1 $2 $3, so do whatever you need to:    
#Perl lets you use any characters as delimiters, i like pipes because      
#they reduce the amount of escaping when using file paths   
m|$regex| && print "$1 : $2 : $3"; 

#alternatively if(m|$regex|) {doOne($1); doTwo($2) ... }  

Aunque si fuera algo más que formatear, implementaría un bucle principal para manejar archivos y completar el cuerpo del script en lugar de confiar en los conmutadores de línea de comandos para el bucle.

1

Esto sólo requiere un pequeño cambio en mis last answer:

paréntesis
my ($guid, $scheme, $star) = $line =~ m{ 
    The [ ] Scheme [ ] GUID: [ ] 
    ([a-zA-Z0-9-]+)   #capture the guid 
    [ ] 
    \( (.+) \)    #capture the scheme 
    (?: 
     [ ] 
     ([*])    #capture the star 
    )?      #if it exists 
}x; 
Cuestiones relacionadas