簡體   English   中英

在 python 中使用正則表達式從文本文件中提取特定字符串

[英]using regex in python to extract specific strings from a text file

我有一個文本文件,其中包含來自 VDHL 代碼編譯的錯誤報告。 我想自動執行廣告[很少需要從該文件中提取一些數據。 我專門尋找位於“[Hierarchy: 'block_ram_inst.”之后的字符串。 在我的例子中是 block_ram_top 或 block_ram_top_1 及其文件路徑。 我還想提取該特定線路的端口名稱。

InOut-Report                         Error     /drive/build/users/tempuser/MCpro/projectphase1/MCpro_phase_1/project227/test_prj/mem/pro_1/pro_1.srcs/sources/code/mem_gen/vhdlcode/ramblock.vhd 241  10   Port 'clk' is not registered [Hierarchy: 'block_ram_inst.block_ram_top']
InOut-Report                         Error     /drive/build/users/tempuser/MCpro/projectphase1/MCpro_phase_1/project227/test_prj/mem/pro_1/pro_1.srcs/sources/code/mem_gen/vhdlcode/ramblock.vhd 113  10   Port 'dina[31:0]' is not registered [Hierarchy: 'block_ram_inst.block_ram_top_1']
InOut-Report                         Error     /drive/build/users/tempuser/MCpro/projectphase1/MCpro_phase_1/project227/test_prj/mem/pro_1/pro_1.srcs/sources/code/mem_gen/vhdlcode/ramblock.vhd 325  10   Port 'clk' is not registered [Hierarchy: 'block_ram_inst.block_ram_top']
InOut-Report                         Error     /drive/build/users/tempuser/MCpro/projectphase1/MCpro_phase_1/project227/test_prj/mem/pro_1/pro_1.srcs/sources/code/mem_gen/vhdlcode/ramblock.vhd 152  10   Port 'clk' is not registered [Hierarchy: 'block_ram_inst.block_ram_top_1']
InOut-Report                         Error     /drive/build/users/tempuser/MCpro/projectphase1/MCpro_phase_1/project227/test_prj/mem/pro_1/pro_1.srcs/sources/code/mem_gen/vhdlcode/ramblock.vhd 318  10   Port 'wea[0]' is not registered [Hierarchy: 'block_ram_inst.block_ram_top']
InOut-Report                         Error     /drive/build/users/tempuser/MCpro/projectphase1/MCpro_phase_1/project227/test_prj/mem/pro_1/pro_1.srcs/sources/code/mem_gen/vhdlcode/ramblock.vhd 289  10   Port 'clk' is not registered [Hierarchy: 'block_ram_inst.block_ram_top_1']

我已經編寫了一個代碼來提取位於層次結構和文件名之后的字符串..但是我無法提取文件的完整路徑和端口名。

這是我的代碼。

with open(filename,'r') as f:
    targets = [line for line in f if "InOut-Report" in line]
    filenames = []
    data = []
    for line in targets:
        match = re.match(r"InOut-Report.*/([-A-Za-z0-9_://.]+).*\[Hierarchy: 'block_ram_inst\.(\w+)']", line)
        if match:
            filenames.append(match.group(1))
            data.append(match.group(2))
print filenames             
print data

我得到的 output 是

['ramblock.vhd', 'ramblock.vhd', 'ramblock.vhd', 'ramblock.vhd', 'ramblock.vhd', 'ramblock.vhd', 'ramblock.vhd', 'ramblock.vhd']
['block_ram_top', 'block_ram_top_1', 'block_ram_top', 'block_ram_top_1', 'block_ram_top', 'block_ram_top_1', 'block_ram_top', 'block_ram_top_1']

但我想在我的 output 中包含文件名的完整路徑……而不僅僅是文件名。 我還想從 sepearte 列表中的每一行中提取端口名稱。

把文件內容當成字符串,可以匹配正則表達式

r'(?m) ((?:\/[\w.]+)+) .* 'block_ram_inst\.([\w.]+)'\]$'

對於每個匹配項,路徑將保存在捕獲組 1 中,端口名稱將保存在捕獲組 2 中。

啟動引擎!

Python 的正則表達式引擎執行以下操作。

  (?m) 
  [ ]
  (                  : begin capture group 1
    (?:\/[\w.]+)     : match '/' then 1+ word chars or periods in a
                       non-capture group    
    +                : execute non-capture group 1+ times
  )                  : end capture group 1
  [ ].*[ ].          : match a space, then 0+ chars then ' .'
  'block_ram_inst\.  : match "'block_ram_inst." 
  ([\w.]+)           : match 1+ words characters of periods in capture
                       group 2
  '\]                : match "']"
  $                  : match end of string

我將上面的空格表示為包含空格 ( [ ] ) 的捕獲組,只是為了讓它們可見。

您發布的正則表達式似乎不起作用,但由於您的問題很明確,我嘗試使用以下正則表達式:

r"InOut-Report\s+Error\s+([-\w://.]+)\s+\d+\s+\d+\s+Port '(\w+)' is not registered \[Hierarchy: 'block_ram_inst\.(block_ram_top(?:_\d)?)'\]"

這里看到它的實際效果

  • InOut-Report :從字面上匹配該字符串,沒什么特別的。
  • \s+\s匹配任何空白字符(空格、制表符、換行符...), +修飾符指定可以有 1 個或多個。
  • ([-\w://.]+)\w表示任何字母數字或下划線 ( A-Za-z0-9_ )。 您還添加了破折號 ( - )、冒號 ( : 、斜杠 ( / ) 和點 ( . )。 現在我再次看到它,第二個斜杠是多余的(它是從你的問題中復制的)所以你可以只留下其中一個。 帶有修飾符[...]+的方括號指定內部列表中的任何字符需要出現 1 次或多次。 被中括號(...)包圍的意思是它是一個捕獲組,路徑。
  • \s+ :見上文。
  • \d+ :與上面類似,但\d表示任何數字( 0-9 ),因此這 1 個或多個數字。
  • \s+ :見上文。
  • \d+ :見上文。
  • \s+ :見上文。
  • Port ' :從字面上匹配該字符串,沒什么特別的。
  • (\w+) :第二個捕獲組 1 個或多個字母數字字符或下划線,端口名稱。
  • ' is not registered \[Hierarchy: 'block_ram_inst\. : 從字面上匹配該字符串,我們只是轉義[. 因為它們有特殊含義,我們想要的是字面字符而不是特殊含義。
  • (block_ram_top(?:_\d)?)block_ram_top是文字字符串,沒什么特別的。 _\d表示下划線后跟數字。 它們在非捕獲組(?:...)內。 非捕獲組允許對部分進行分組,但不會像我們對路徑或端口名稱所做的那樣保存它們供以后使用。 在這種情況下,我們將它們分組以應用? 可以在后面找到的修飾符。 這意味着它可以是 0 次或 1 次。 那么(?:_\d)? 意味着可以有一個下划線后跟一個數字或沒有。 所有這些都被一個捕獲組(...)包圍,該捕獲組會將其保存為第三個值。
  • \] :文字字符]再次轉義以指定我們需要文字字符並且我們不將其用作特殊字符。

您還可以進一步簡化它:

r"([-\w://.]+)[\s\d]+Port '(\w+)' is not registered \[Hierarchy: 'block_ram_inst\.(block_ram_top(?:_\d)?)'\]"

這里看到它的實際效果

簡化只是與路徑和組\s+\d+\s+\d+\s+之前的部分不匹配,因為[\s\d]+只是將空格和數字視為一個整體,因為我們不需要捕獲數字。

在評論中提出了另一個修改:

r"([-\w://.]+)[\s\d]+Port '(\w+)' is not registered \[Hierarchy: 'block_ram_inst\.(\w+)'\]"

唯一的修改是在第三個捕獲組中,以前只采用block_ram_topblock_ram_top_后跟一個數字,現在考慮任何帶下划線的字母數字字符。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM