extraer cadena antes de los números y después del guión bajo

extraer cadena antes de los números y después del guión bajo

La cadena original es así:

str-str001-002_01
str-str005-006_05

Me gustaría extraer la cadena antes del número y después del guión bajo, por lo que sería así:

str-str_01
str-str_05

Recuerdo que sed podía separar el patrón en grupos como este:

 sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\1\3/p'

pero imprime:

str-str0002_01

Luego recuerdo que [0-9] es solo un número, así que lo probé con el signo + o *. Entonces da un resultado vacío.

pd: usando

echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]-[0-9]\)\(.*$\)/\2/p'

Puedo ver que coincide 1-0.

Luego lo probé con:

echo 'str-str001-002_01' | sed -n 's/\(^.*\)\([0-9]\+-[0-9]\+\)\(.*$\)/\2/p'

dejo los primeros 2 numeros, y solo coincide

1-002

Entonces, ¿cómo hacer que coincida?001-002

Respuesta1

Esto proporciona el resultado requerido:

sed -nE 's/^([^0-9]*).*_([^_]+)$/\1_\2/p'

Salida de su ejemplo

str-str_01
str-str_05

Explicación

  • sed -nE 's/…/…/p'- Utilice ERE, no imprima líneas a menos que coincidan
  • ^- anclar al inicio de la línea
  • ([^0-9]*)- coincidir con un patrón lo más largo posible, es decir, al menos un carácter que no sea un dígito
  • .*_- coincidir tanto como sea posible (sin incluir nada), seguido de " _"
  • ([^_]+)- hacer coincidir un patrón lo más largo posible (al menos un carácter) que no sea un guión bajo
  • $- anclar hasta el final de la línea
  • \1_\2- reemplazar toda la línea con la primera (…)coincidencia, " _", y la segunda (…)coincidencia

La razón por la que sus intentos no funcionaron como esperaba es porque *(y +) es codicioso: consumirá tantos caracteres como sea posible que coincidan con el átomo anterior. Entonces, para un ERE de (.*)([0-9]+)aplicado a algo como abc123, se .* consumirá abc12, dejando [0-9]+que coincida solo 3. Necesitarías un "no dígito" para limitar el primer partido: ([^0-9]*)([0-9]+)obtener abcy 123.

Respuesta2

$ cat file
str-str001-002_01
str-str005-006_05
$ sed 's/[0-9]\{3\}-[0-9]\{3\}//' file
str-str_01
str-str_05

El comando de sustitución aquí es hacer coincidir y eliminar NNN-NNNdonde NNNhay una serie de tres dígitos.

para igualaral menos unodígito, utilizar 1,en lugar de 3:

$ sed 's/[0-9]\{1,\}-[0-9]\{1,\}//' file
str-str_01
str-str_05

Esto corresponde al uso +en una expresión regular extendida. Las expresiones regulares utilizadas de sedforma predeterminada son expresiones regulares "básicas" y +coincidirían con un carácter más literal. La mayoría de sedlas implementaciones también admiten expresiones extendidas con -E:

$ sed -E 's/[0-9]+-[0-9]+//' file
str-str_01
str-str_05

Usar *, como en [0-9]*-[0-9]*, no funcionaría ya que coincidiría con el guión str-str(que tiene cero dígitos a su alrededor).


Si sientes que realmente tienes que hacer coincidir toda la línea y capturar las partes que deseas conservar, entonces también puedes hacerlo. El siguiente comando captura los no dígitos iniciales y el bit final, incluido el guión bajo:

$ sed 's/\([^0-9]*\).*\(_.*\)/\1\2/' file
str-str_01
str-str_05

Esto, sin embargo, en mi humilde opinión es un poco difícil de descifrar y hace suposiciones sobre el inicio y el final de la cadena que nunca mencionaste en la pregunta. El inicio no puede, por ejemplo, contener dígitos antes de los dígitos que desea eliminar, y el final de la cadena se cortará en elúltimoguión bajo, no necesariamente después de los dígitos que desea eliminar si hay varios guiones bajos en esa parte de la cadena.

Siempre puedes agregar más a esta expresión para asegurarte de que NNN-NNNno se capture solo el bit, pero eso haría aún más difícil entender la expresión.

información relacionada