sil*_*nky 5 python regex perl seek
我正在尝试在文件中寻找令牌 ':path,',然后将以下所有(任意数字计数)数字读取为数字(因此对于 ':path,123' 我寻找 , in file 然后读取整数 123)。然后读取当前搜索位置和 pos+123 之间的字符(将它们存储在列表中或其他任何位置)。然后寻找直到下一个匹配 ':path' 并重复该过程。
我想要一个有点像的功能:
def fregseek(FILE, current_seek, /regex/): . . value_found = ? # :path,[0-9]+ 之后读取下 N 个字符的结果 . . 返回 next_start_seek, value_found
一行中可能有任意数量的 ':path,' 匹配项,并且该字符串可能出现在 ',' 之后指定的字符数内。我写了一堆乱七八糟的垃圾,在每一行中读取,然后对于匹配指示的前 N 个字符的每一行 chomps,然后继续处理字符串,直到它全部被吃掉。然后读取下一个字符串,依此类推。
这太可怕了,当我真正需要做的只是查找时,我不想从一个潜在的巨大文件中删除所有行(特别是因为换行符无关紧要,所以有一个额外的处理步骤只是因为行很容易从文件中提取是荒谬的)。
所以,就是这样,这就是我想要解决的问题。我需要寻找匹配项,读取一个值,从该值的末尾继续寻找下一个匹配项,依此类推,直到文件用完为止。
如果有人能帮我解决这个问题,我会很高兴收到他们的来信:)
如果可能的话,我想避免使用非标准库,我也想要最短的代码,但这是我最不关心的(速度和内存消耗是重要因素,但我不希望额外的 50 loc 只是为了引导一些一个带有小功能的库,如果我知道它是什么,我就可以撕掉它)。
我更喜欢 python 代码,但是,如果 perl 在这方面胜过 python,我将使用 perl,我也愿意接受聪明的 sed/awk/bash 脚本等,只要它们不是特别慢。
首先十分感谢。
如果您不需要正则表达式,则只需查找和切片即可完成此操作。
\n无论哪种方式,简单的解决方案是将整个文件读入内存,然后查找并切片结果str/bytes对象。
但是,如果您不能(或不想)将整个文件读入内存,则这不起作用。
\n幸运的是,如果您可以确信您的文件 << 2GB,或者您只需要在 64 位 Python 中工作,并且您使用的是合理的平台(POSIX、现代 Windows 等),那么您mmap可以文件存入内存。该mmap对象具有与字符串相同的方法的子集,因此您可以假装您有一个字符串,就像您将整个文件读入内存一样,但您可以依靠 Python 实现和操作系统来实现它只是以合理的效率工作。
根据您的 Python 版本,re可能无法像扫描字符串一样扫描 mmap,它可能可以工作但速度很慢,或者可能工作得很好。因此,您不妨先尝试一下,如果它没有抛出异常或比您预期的速度慢得多,那么您就完成了:
def findpaths(fname):\n with open(fname, \'rb\') as f:\n m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)\n for match in re.finditer(\':path,([0-9]+)\', m):\n yield m[match.end():match.end()+int(match.group(1))]\nRun Code Online (Sandbox Code Playgroud)\n(这与 BrtH\ 的答案相同,只是使用 mmap 而不是字符串,并重组为生成器而不是列表\xe2\x80\x94,尽管当然你可以通过替换他的方括号来完成后一部分带括号。)
\n如果您使用的是旧版(或非 CPython?)Python 版本,无法(有效地)re执行mmap,则情况会更复杂一些:
def nextdigits(s, start):\n return \'\'.join(itertools.takewhile(str.isdigit,\n itertools.islice(s, start, None)))\n\ndef findpaths(fname):\n with open(fname, \'rb\') as f:\n m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)\n i = 0\n while True:\n n = m.find(\':path\', i)\n if n == -1: return\n countstr = nextdigits(m, n+6)\n count = int(countstr)\n n += 6 + len(countstr)\n yield m[n:n+count]\n i = n + 6 + count\nRun Code Online (Sandbox Code Playgroud)\n这可能不是编写该nextdigits函数的最快方法。我不确定这实际上是否重要(计时并查看),但如果确实如此,其他可能性是将m[n+6:n+A_BIG_ENOUGH_NUMBER]其切片并正则表达式,或编写自定义循环,或 \xe2\x80\xa6 另一方面,如果这是您的瓶颈,那么切换到具有 JIT 的解释器(PyPy、Jython 或 IronPython)\xe2\x80\xa6 可能会带来更多好处
对于我的测试,我将事情分开:findpaths接受一个类似字符串的对象,调用者执行with open和mmap位,然后m传入findpaths; 我没有在这里这样做只是为了简洁。
无论如何,我已经根据以下数据测试了两个版本:
\ndef nextdigits(s, start):\n return \'\'.join(itertools.takewhile(str.isdigit,\n itertools.islice(s, start, None)))\n\ndef findpaths(fname):\n with open(fname, \'rb\') as f:\n m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)\n i = 0\n while True:\n n = m.find(\':path\', i)\n if n == -1: return\n countstr = nextdigits(m, n+6)\n count = int(countstr)\n n += 6 + len(countstr)\n yield m[n:n+count]\n i = n + 6 + count\nRun Code Online (Sandbox Code Playgroud)\n输出是:
\nabc\nabcdefghij\nabc\n\nabc\nRun Code Online (Sandbox Code Playgroud)\n我认为这是正确的?
\n如果我的早期版本导致它以 100% CPU 运行,我的猜测是我没有i在循环中正确递增;这是在紧密的解析循环中获得该行为的最常见原因。无论如何,如果您可以用当前版本重现该内容,请发布数据。
| 归档时间: |
|
| 查看次数: |
2627 次 |
| 最近记录: |