【问题标题】:Python multi-line pattern matchingPython多行模式匹配
【发布时间】:2014-09-19 20:48:58
【问题描述】:

我正在尝试通过 python 使用 shell 命令匹配多行模式。

我可以使用 shell 命令进行匹配,但我无法通过 Python subprocess.call 或 os.system 模块传递此命令。

我的文件看起来像这样:

(CELL
  (CELLTYPE "NAND_2X1")
  (INSTANCE U2)
  (DELAY
    (ABSOLUTE
    (IOPATH A1 ZN (0.02700::0.02700) (0.01012::0.01012))
    (IOPATH A2 ZN (0.02944::0.02944) (0.00930::0.00930))
    )
  )
)

不,我正在尝试提取这个:

  (INSTANCE U2)
  (DELAY
    (ABSOLUTE
    (IOPATH A1 ZN (0.02700::0.02700) (0.01012::0.01012))
    (IOPATH A2 ZN (0.02944::0.02944) (0.00930::0.00930))
    )
  )

使用这个正则表达式:

pcregrep -M -n 'INSTANCE U2((?!^\)).*\n)+' sdf/c1_syn_buf2.sdf

其中U2是搜索字符串,sdf/c1_syn_buf2.sdf是文件名

在 Python 中,我定义了一个函数,我将向其传递搜索字符串和文件名,因为我必须多次执行此操作。

我无法使用以下命令作为 shell 命令成功执行此命令:

>>>b = subprocess.call(['pcregrep','-M','-n','INSTANCE '+arg, '\)((?!^\).*\n)+ '+file ])
pcregrep: Failed to open \)((?!^\).*
)+ /home/sanjay/thesis/code/sdf/c7552_syn_buf0.sdf: No such file or directory

当我实际输入参数(在本例中为 U2)名称和文件名时,我能够获得所需的输出。

编辑 如果 pcregrep 不够友好,这里是 awk 命令:

awk '/INSTANCE U2/,/^)\n?/' sdf/c1_syn_buf2.sdf

返回相同。

有人可以帮我解决这个问题吗?

【问题讨论】:

  • 我想你只是有一个错字: .*\n)+ '+file 它可能应该是 .*\n)+ ',文件用逗号而不是加号
  • @rkh 不是错字,括号里的内容基本上是(.*\n)+,我添加了(?!\)),表示匹配只需要在以@987654328开头的行之前进行遇到@。
  • 我认为,分隔 arg 和 ') 的逗号也应该是 +,以便列表中的元素是子进程调用的单个参数

标签: python subprocess pcregrep


【解决方案1】:

运行 shell 命令:

$ pcregrep -M -n 'INSTANCE U2((?!^\)).*\n)+' sdf/c1_syn_buf2.sdf

在 Python 中:

from subprocess import check_output as qx

output = qx(['pcregrep', '-M', '-n', r'INSTANCE {}((?!^\)).*\n)+'.format(arg),
             path_to_sdf])
  • 使用 r'' 字面量或将所有反斜杠加倍
  • 将每个 shell 参数作为单独的列表项传递

另外,你不需要pcregrep,你可以用Python搜索文件:

import re
from mmap import ACCESS_READ, mmap

with open(path_to_sdf) as f, mmap(f.fileno(), 0, access=ACCESS_READ) as s:
    # arg = re.escape(arg) # call it if you want to match arg verbatim
    output = re.findall(r'INSTANCE {}((?!^\)).*\n)+'.format(arg).encode(), s,
                        flags=re.DOTALL | re.MULTILINE)

mmap 用于容纳不适合内存的文件。它还可能在 Windows 上运行得更快。

【讨论】:

  • @Sebastian 我对 python 还很陌生,因此使用的是 Unix 命令。感谢 mmap 方法,它工作得很好!感谢 qx 的 perl 方法
【解决方案2】:

只看你原来的命令行,并将调用格式化为每行一个 arg,不应该是这样吗?

b = subprocess.call(
['pcregrep',
    '-M',
    '-n',
    'INSTANCE {}\)((?!^\)).*\n)+ '.format(arg),
    file ])

我不太确定括号和反斜杠。这些在正则表达式中总是有点棘手。你可能需要稍微摆弄一下才能得到你想要的东西(在 python 文档中查看 r'' 正则表达式字符串类型)

【讨论】:

  • 我没有得到这个,我想在搜索字符串中有arg
  • 格式行会将 arg 放入搜索字符串中。如果 arg 设置为“Hello”,则 'INSTANCE {})((?!^).*\n)+ '.format(arg) 等于 'INSTANCE hello)((?!^).*\n )+ '(加或减一些反斜杠)
  • hmm...我其实刚试了一下,现在pcregrep报错:>>> b = subprocess.call(['pcregrep','-M','-n','INSTANCE {}\)((?!^\).*\n) '.format(arg),file ]) pcregrep: Error in command-line regex at offset 25: missing )
  • 我希望 Python 有一个简单的反引号或 exec 方法,比如 perl!
  • 看看你原来的正则表达式,我想我忘了中间有一个额外的')'。我刚刚编辑过。希望反斜杠是正确的......
【解决方案3】:

看来我需要使用格式说明符%s

当我使用它时它工作:

b = subprocess.check_output("pcregrep -M -n 'INSTANCE '%s'((?!^\)).*\n)+' {} ".format(file) %arg,shell=True)

有了这个,我得到了变量b的完全匹配

我使用 %s 传递参数,使用 {} .format 方法传递文件名

【讨论】:

  • 您应该使用%.format 字符串格式。同时使用两者看起来很难看。
猜你喜欢
  • 2011-02-12
  • 2018-01-28
  • 2010-11-26
  • 1970-01-01
  • 2021-06-15
  • 2016-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多