OS X:如何在 600mb json 文件中有效地查找周围有 100 个字符上下文的文本?



我有一个大的缩小text.json文件,我需要在其中找到一个特定的短语dasdhfb347rbf并打印出周围的短语,例如 100 个字符的上下文(前导/尾随)。

我已经尝试过grep -Eo '.{0,100}dasdhfb347rbf.{0,100}' /dir/text.json但它似乎永远悬而未决。

附言。我有一台带有i7 CPU,8GB RAM和SSD驱动器的Macbook。

正如 Mark Setchell 在他的回答中指出的那样,您在.{0,100}中使用(未转义的){}来匹配多达 100 个字符。 需要使用-E来启用扩展正则表达式(正则表达式); 或者,您可以使用转义(使用默认的基本正则表达式):.{0,100}.

但是,这两种更正都不能解决您的问题,这是一个性能问题grep,整个文件 - 因为它缩小的JSON--是一行,并且您的特定正则表达式会导致惊人的长执行时间(取决于您的硬件,大约10 +分钟与600MB文件;大概,您的正则表达式需要大量的回溯)。

使用LC_ALL=C,正如Yreg的回答所建议的那样,带来了轻微的改进,但不足以产生真正的差异(LC_ALL=C简化了字符处理,因为每个字节都被假定为ASCII字符)。

切换到文本字符串匹配可显著提高性能,但虽然grep确实支持文本匹配,但它不支持报告基于字符的上下文(仅基于行)。

因此,要使用的工具是awk,它提供了用于文字字符串匹配和基于位置的子字符串提取的函数:

awk -v RS='3' -v txt='dasdhfb347rbf' -v n=100 '
BEGIN { 
getline; s = $0               # read the entire file
while (pos=index(s, txt)) {   # loop over matches
len = length(txt) + 2 * n - (pos - n < 1 ? n - pos + 1 : 0)
print substr(s, pos-n, len)
s = substr(s, pos -n + len)
}
}
' text.json

以上应该表现得更好。

请注意,需要v RS='3'才能使 BSD Awk 一次读取整个文件(-v RS='^$'通常用于 GNU Awk 和 Mawk,但这不适用于 BSD Awk);请注意,这种技术依赖于控制字符0x3而不是文本的一部分。

附带说明一下:

  • GNUAwk,你可以通过Homebrew安装,比我机器上的BSD Awk快两倍多。

  • Mawk(也可以通过Homebrew安装)通常是最快的Awk,在这里不是一个选项,因为它似乎对行长度有硬性限制。

尝试更改区域设置。

LC_ALL=C grep -o…

我认为您需要在macOS上使用-E选项来允许使用扩展正则表达式:

# without "-E", finds nothing
echo abcdefghijk | grep -o ".def.{3}"
# with "-E", finds regex
echo abcdefghijk | grep -Eo ".def.{3}"
cdefghi

最新更新