快速提取两个字符串第一次出现之间的文件部分

快速提取两个字符串第一次出现之间的文件部分

我有包含一行的大型 (MB) 文本文件,需要提取 string1 和 string2 第一次出现之间的部分。我发现了很多食谱,但大多数适用于单独的行或提取到第二个字符串的最后一次出现。我发现使用参数 infile、outfile、string1、string2 可以工作的是:

#!/bin/bash

a="$(cat $1)"                   ## copy file1 to a

a="$(echo "${a#*"$3"}")"        ## cut up to (including) str1  

echo "${a%%"$4"*}" > $2         ## part after str1 up to str2

## where the last line may also be

printf '%s' "${a%%"$4"*}" > $2  ## part after str1 up to str2

但这两个版本都非常慢(我必须为每个文件重复多次)。怎么提速?

答案1

与 OP 聊天时的一些讨论表明,该单行是来自网络查询的 JSON。使用诸如jq . < input_file或 之类的工具漂亮地打印此文件python -mjson.tool input_file,使文件更适合传统的逐行处理。

进一步的讨论表明这是一个书目查找,其目的是生成一个平面文件。jqOP 认为以下程序(我的第一个程序)足够快。

#!/bin/bash                                                                                                                           

jq -r  < "$1" '.response.docs[] |                                                                                          
    ("    Title: "+.title[]),                                                                                                          
    ("   Authors: "+(.author|join(""))),                                                                                               
    ("    Bibcode: "+.bibcode),                                                                                                        
    ("   AltBibcode: "+(.alternate_bibcode//[] | join(" : "))),                                                                        
    ("  "+(.abstract//"NOABSTRACT")),                                                                                                  
    ""' | fmt | sed 's/^    \?//'

有几个微妙的点。我们的愿望是包装摘要而不是一长行,因此输出通过 发送fmt。该程序具有以下属性:以不同缩进开头的行不是连接在一起,因此在文本中添加 4/3/4/3/2 空格模式,例如“标题:”。然后,fmt 实际上只是包装了摘要,缩进了 2 个空格。然后使用 sed 删除其他标题行上的 3 或 4 个空格。这并不完美,很长的作者列表也会被包装起来。更好的 sed 程序可以将作者重新连接到一行,删除空白的 AltBibcode 条目等。

输出格式经过精心设计,可以通过 awk 一行脚本进行后期处理

awk -vRS='' -vORS=$'\n\n' !/NOABSTRACT/'

删除没有摘要的条目。

答案2

$ sed -e 's/stringA/\n/;s/.*\n//;s/stringB.*//' file 

删除 stringA 之前的代码分两个阶段完成(将 stringA 更改为换行符,然后删除第一行),而不是更明显的“删除 stringA 之前的所有内容”,因为删除需要达到第一的stringA 的出现而不是最后一个。与许多其他工具(例如 python 和 perl)不同,sed 不支持非贪婪正则表达式。

$ perl -lpe '
    my($sa, $sb) = qw/stringA stringB/;
    my $p2 = index($_, $sb);
    my $p1 = index($_, $sa)+length($sa);
    $_ = substr($_, $p1, $p2-$p1);
'  file

相关内容