2016-05-07 13 views
0

Ich brauche einige Daten aus einem String wie dieser (VHDL-Code) zu extrahieren:python regex Suche bis Klammer Spiel

entBody = """entity pci_bfm is                
    generic(                 
    G_INST_NAME   : string   := "PCI_BFM";     
    G_HANDLE_NO   : rpciBfmHandleNo := 0;       
    G_IDSEL_POS_EXT_TARGET : idsel_pos  := 30;       
    G_IDSEL_POS_INT_TARGET : idsel_pos  := 29       
    );                  
    port(                  
    i_tb_stop : in boolean;      -- Testbench global sto 
    o_clk  : out std_logic;      -- PCI clock.   
    o_rstn  : out std_logic;      -- PCI reset.   
    o_idsel : out std_logic;      -- Initialization devic 
    i_reqn  : in std_logic;      -- Request. The reqn in 
    o_gntn  : out std_logic;      -- Grant. The gntn onpu 
    io_ad  : inout std_logic_vector(31 downto 0); -- Address/data bus. Th 
    io_cben : inout std_logic_vector(3 downto 0); -- Command/byte enable. 
    io_par  : inout std_logic;      -- Parity. The par sign 
    io_framen : inout std_logic;      -- Frame. The framen si 
    io_irdyn : inout std_logic;      -- Initiator ready. The 
    io_devseln : inout std_logic;      -- Device select. Targe 
    io_trdyn : inout std_logic;      -- Target ready. The tr 
    io_stopn : inout std_logic;      -- Stop. The stopn sign 
    io_perrn : inout std_logic;      -- Parity error. The pe 
    i_serrn : in std_logic;      -- System error. The se 
    i_intan : in std_logic;      -- Interrupt A. The int 
    o_lockn : out std_logic      -- Locked operations. R 
    );                  
end entity pci_bfm;""" 

Die VHDL Kommentare nicht alle die gleiche Größe haben, ich abgeschnitten sie leichter zu sein, lesen.

Ich bin daran interessiert, alles zwischen 'port (' und last ') zu bekommen;' (die, die Port-Deklarationen schließt). Natürlich sind die VHDL-Deklarationen nicht gut eingerückt und wie hier formatiert.

Ich habe eine Python 2.7.x Regex dafür:

pattern = re.compile("port\s*\((.*?)\s+\)\s*;") 
match3 = pattern.search(entBody) 
ports = match3.group(1) 

Es funktioniert gut, wenn der Schluss); ist nicht unmittelbar nach der letzten Deklaration. Im Folgenden wird nicht funktionieren:

entBody2 = """entity QSPI_FLASH_SPANSION_S25FL_BFM is 
    generic 
    (
     G_INST_NAME : string := "QSPI_FLASH_SPANSION_S25FL_BFM"; 
     G_HANDLE_NO : integer := 2 
    ); 
    port (
    tb_stop : in boolean;      -- Testbench global stop. 
    sclk : in std_logic; 
    csn  : in std_logic; 
    sdat : inout std_logic_vector(3 downto 0)); 
end;""" 

Wenn ich meine Regex ein wenig wie das ändern:

pattern = re.compile("port\s*\((.*?)\s*\)\s*;") # \s* instead of \s+ 

dann die Suche am Ende wird 'io_ad: inout std_logic_vector (31 downto 0', die nicht ist überhaupt gut.

ich habe mich gefragt, ob ich Regex zu einer Suche wie diese verwenden kann, das heißt zu zählen Klammer zu öffnen und nur zu stoppen, wenn alle Klammern geschlossen sind.

wenn die Re ist keine einfache Möglichkeit, ich werde eine einfache String-Suche mit String-Funktionen tun, um es zu lösen.

Vielen Dank.

+0

* Ich abgeschnitten sie leichter sein * zu lesen - sind Sie sicher, dass Sie erhalten das gleiche Format? Wie können Sie die führenden/nachlaufenden Grenzen und den Inhalt definieren? –

Antwort

0

Hier möchten Sie die Zeichen einschließlich Newline übereinstimmen. Verwenden Sie also das Muster \s\S in einer Zeichenklasse.

\s passen Sie die beliebigen Leerzeichen an.

\S Spiel die jedes nicht Leerzeichen

match3 =re.search(r"port\(([\s\S]+?)\);\s+\n",entBody) 

Or S flag. Hilft bei der Übereinstimmung mit allen Zeichen einschließlich Zeilenumbrüchen.

match3 =re.search(r"port\((.+?)\);\s+\n",entBody,re.S) 
+0

Ein Wort der Warnung: Dies wird den gesamten Text zwischen 'port (' und _the last closing parens ')' im gesamten Text erfassen. Obwohl es in diesem speziellen Fall funktionieren mag, bezweifle ich, dass dies eine gute Lösung für reale Szenarien ist. Alles, was Sie tun müssen, um diese Lösung zu lösen, ist, den 'generic'-Bereich nach dem' port'-Bereich zu verschieben. –

+0

@Rawing Vielen Dank für Ihren Kommentar Beitrag bearbeitet – mkHun

0

können Sie folgende regex verwenden:

/port\s*\((.+)\)\s*;/s 

es Breaking down:

port   # matches the characters port literally (case sensitive) 
\s*    # match any white space character [\r\n\t\f ] Between zero and unlimited times 
\(    # matches the character (literally 
(.+)   # capturing group start - matching any character - Between one and unlimited times 
\)    # matches the character) literally 
\s*    # match any white space character [\r\n\t\f ] Between zero and unlimited times 
;    # matches the character ; literally 

s    # modifier: single line. Dot matches newline characters 

REGEX DEMO

IDEONE DEMO


UPDATE: Wenn es einen Fall gibt, wenn es etwas anderes nach dem port(...) ist, können Sie folgende Regex überprüfen:

/port\s*\((.*?)(?:\)\s*;\s*\w)/s

+0

Dies funktioniert nur, wenn "port" ist der letzte Abschnitt im Code. Wenn beispielsweise der Abschnitt "generic" unterhalb des Abschnitts "port" liegt, würde dies nicht funktionieren. Möglicherweise möchten Sie auch Leerzeichen zwischen den schließenden Zeichen und dem Semikolon zulassen. –

+0

@Rawing Danke. Ich werde an den Änderungen arbeiten, die Sie erwähnt haben. – AKS