extrayendo código de una cadena usando regex en python

Estoy tratando de extraer el código ensamblador de la cadena, pero la expresión regular no era correcta porque solo puedo extraer los códigos de operación, no el código de instrucciones.

import re
text = """
┌ 38: fcn.00014840 ();
│           ; var int64_t var_38h @ rsp+0xffffffd0
│           0x00014840      53             push rbx
│           0x00014841      31f6           xor esi, esi
│           0x00014843      31ff           xor edi, edi
│           0x00014845      e846f2feff     call sym.imp.getcwd
│           0x0001484a      4885c0         test rax, rax
│           0x0001484d      4889c3         mov rbx, rax
│       ┌─< 0x00014850      740e           je 0x14860
│       │   ; CODE XREF from fcn.00014840 @ 0x14868
│      ┌──> 0x00014852      4889d8         mov rax, rbx
│      ╎│   0x00014855      5b             pop rbx
│      ╎│   0x00014856      c3             ret
..
│      ╎│   ; CODE XREF from fcn.00014840 @ 0x14850
│      ╎└─> 0x00014860      e88beffeff     call sym.imp.__errno_location
│      ╎    0x00014865      83380c         cmp dword [rax], 0xc
│      └──< 0x00014868      75e8           jne 0x14852
└           0x0001486a      e861feffff     call fcn.000146d0
            ; CALL XREFS from fcn.00013d00 @ 0x13d9d, 0x13da8
"""

print("\n".join(re.findall('0x[0-9a-fA-F]{8}[0-9a-fA-F](.*?)',text)))

así que quiero la salida como esta:

push rbx
xor esi, esi
xor edi, edi
call sym.imp.getcwd
test rax, rax
mov rbx, rax
je 0x14860
mov rax, rbx
pop rbx
ret
call sym.imp.__errno_location
cmp dword [rax], 0xc
jne 0x14852
call fcn.000146d0
Answer

Puedes probar esto:

out = "\n".join(re.findall(r"0x[0-9a-fA-F]{8} +[^ ]+ +([a-z].*)", text))
print(out)

Da:

push rbx
xor esi, esi
xor edi, edi
call sym.imp.getcwd
test rax, rax
mov rbx, rax
je 0x14860
mov rax, rbx
pop rbx
ret
call sym.imp.__errno_location
cmp dword [rax], 0xc
jne 0x14852
call fcn.000146d0

En su patrón 0x[0-9a-fA-F]{8}[0-9a-fA-F], hace coincidir un solo carácter [0-9a-fA-F]después de los 8 caracteres anteriores, pero eso no existe en los datos de ejemplo, por lo que no habrá coincidencia.

Además, el grupo de captura al final (.*?)no es codicioso sin que nada siga el patrón. Como coincidencias no codiciosas lo menos posible, este grupo siempre estará vacío.

Para el patrón, puedes usar:

\b0x[0-9a-f]{8}[^\S\n]+[0-9a-f]+[^\S\n]+(.+)

El patrón coincide:

  • \b0x[0-9a-f]{8} Un límite de palabra para evitar una coincidencia de palabra parial
  • [^\S\n]+ Coincide con 1+ caracteres de espacio en blanco sin saltos de línea
  • [0-9a-f]+ Coincidir 1+ veces cualquiera de los rangos enumerados 0-9 af
  • [^\S\n]+ Coincide con 1+ caracteres de espacio en blanco sin saltos de línea
  • (.+)Capture el grupo 1 , haga coincidir el resto de la línea (que será devuelto por re.findall)

Demostración de expresiones regulares

Ejemplo usando una coincidencia que no distingue entre mayúsculas y minúsculas:

print("\n".join(re.findall(r"\b0x[0-9a-f]{8}[^\S\n]+[0-9a-f]+[^\S\n]+(.+)", text, re.I)))

Producción

push rbx
xor esi, esi
xor edi, edi
call sym.imp.getcwd
test rax, rax
mov rbx, rax
je 0x14860
mov rax, rbx
pop rbx
ret
call sym.imp.__errno_location
cmp dword [rax], 0xc
jne 0x14852
call fcn.000146d0

Puede usar re.subpara convertir coincidencias de la siguiente expresión regular en picaduras vacías:

(?m)^(?:(?!.{12}0x[\da-fA-F]{8}).*\r?\n|.{43})

Expresión regular de Python < ¯\ (ツ)> Código de Python

La expresión regular se puede dividir de la siguiente manera (también se puede pasar el cursor sobre cada parte de la expresión en el enlace "Python regex" para obtener una explicación de su función).

(?m)              # set multiline flag causing '^' and '$' to match
                  # the beginning and end of each line respectively
^                 # match beginning of line
(?:               # begin non-capture group
  (?!             # begin negative lookahead
    .{12}0x       # match 12 characters followed by '0x'
    [\da-fA-F]{8} # match 8 characters contained in the character class
  )               # end negative lookahead
  .*\r?\n         # match the entire line including the terminator
|                 # or
  .{43}           # match 43 characters
)                 # end non-capture group