Regex 提取短语后的所有文本,然后在每行开头添加文件名?
我正在做一个有3k个文本文档的文献计量学项目,我试图找出如何从非结构化文本到引用列表。格式变化很大,但都以引用的作品结尾。到目前为止,我已经想到了这个:Regex 提取短语后的所有文本,然后在每行开头添加文件名?,regex,perl,sed,Regex,Perl,Sed,我正在做一个有3k个文本文档的文献计量学项目,我试图找出如何从非结构化文本到引用列表。格式变化很大,但都以引用的作品结尾。到目前为止,我已经想到了这个: sed -n '/Works Cited/,$p' Jones.txt > newfile.txt 在所有~3k文档上运行之后,我将合并它们进行分析。但知道哪一行/引用来自哪一份文件是有意义的。因此,我最好的猜测是,这将涉及两个步骤: 摘录引用的短语“作品”后面的行 在每行的开头插入文件名。(没有标准的元数据结构,甚至没有出现作者、标题
sed -n '/Works Cited/,$p' Jones.txt > newfile.txt
在所有~3k文档上运行之后,我将合并它们进行分析。但知道哪一行/引用来自哪一份文件是有意义的。因此,我最好的猜测是,这将涉及两个步骤:
awk
您没有提到您的操作系统,但假设您可以访问GNUawk
,请尝试:
$ awk 'FNR==1{f=0} f && /./{printf "%s, ", FILENAME} f{print} /Works Cited/{f=1}' *.txt
Jones.txt, Jones, Ted. Biology. New York: Penguin, 2009.
Jones.txt, Smith, Mary. "Butterflies and Biology." Journal 21.2 (2013): 1-10.
for f in *.txt
do
sed -n '/Works Cited/,${/Works Cited/d; /./ s/^/'"$f, /;p}" "$f"
done
注意,在这个解决方案中,您可以通过上述示例中的*.txt
在命令行上一次指定所有文件名,GNUawk
在变量FILENAME
从一个文件切换到下一个文件时更新该变量
工作原理:
在每个文件的第一行,将flagFNR==1{f=0}
设置为零,表示我们尚未看到该文件引用的f
作品
如果标志f&&/{printf“%s”,FILENAME}
非零(意思是已经看到f
),并且如果行非空(行上至少有一个字符),则打印文件名,后跟逗号和空格引用的作品
如果标志f{print}
非零,则打印整行f
如果此行包含引用的/引用作品/{f=1}
,则将标志作品
设置为一f
FILENAME
变量是GNU扩展名
非GNUawk
对于不支持FILENAME
的awk
版本,我们可以使用shell循环,依次将awk
变量name
设置为每个文件的名称:
for f in *.txt
do
awk -v name="$f" 'f && /./{printf name ", "} f{print} /Works Cited/{f=1}' "$f"
done
使用sed
如果确实必须使用sed
,请尝试:
$ awk 'FNR==1{f=0} f && /./{printf "%s, ", FILENAME} f{print} /Works Cited/{f=1}' *.txt
Jones.txt, Jones, Ted. Biology. New York: Penguin, 2009.
Jones.txt, Smith, Mary. "Butterflies and Biology." Journal 21.2 (2013): 1-10.
for f in *.txt
do
sed -n '/Works Cited/,${/Works Cited/d; /./ s/^/'"$f, /;p}" "$f"
done
如果您确信您的文件名不包含任何sed活动字符,那么这种方法是可以接受的。您可以通过一个简单的perl脚本一步完成这一点 基本用法:
extract.pl myoutfile.txt
以下是脚本:
#!/usr/bin/env perl
use strict 'vars';
use warnings;
use feature qw/say/;
my $outfile = $ARGV[0] || 'citations.out';
my $split_on = $ARGV[1] || 'Works Cited';
my $filetypes = $ARGV[2] || 'txt';
# Open Outfile
open(my $fh_outfile, '>', $outfile)
or die "Could not open file '$outfile' $!";
# Get list of files
my @files = <*.$filetypes>;
my $count = scalar @files;
my $current = 0;
# Scan files
foreach my $file (@files) {
say "\nWorking on: $file [ " . ++$current . " / $count ]";
# Read in the file contents
my @contents = do {
open my $fh, "<", $file
or die "Could not open $file $!";
<$fh>;
};
my $split_found = 0;
foreach my $line ( @contents ) {
# Write to output file, only when in
# works cited section, and line isn't empty
if ( $split_found && $line =~ m/\w/ ) {
print $fh_outfile "$file, $line";
print " >$file, $line";
}
# Flag 'Works Cited' section
$split_found = $split_found || $line =~ m/^$split_on\s*$/g;
}
};
close $fh_outfile;
#/usr/bin/env perl
使用严格的“变量”;
使用警告;
使用功能qw/say/;
我的$outfile=$ARGV[0]| |'引文.out';
我的$split_on=$ARGV[1]| |“引用的作品”;
my$filetypes=$ARGV[2]||“txt”;
#开放式出铁口
打开(我的$fh_输出文件,'>',$outfile)
或“无法打开文件“$outfile”$!”;
#获取文件列表
我的@files=;
我的$count=标量@文件;
我的$current=0;
#扫描文件
foreach my$文件(@files){
说“\n处理:$file[”++$current./$count]”;
#读入文件内容
我的@contents=do{
打开我的$fh,“$file,$line”;
}
#国旗‘引用作品’组
$split_found=$split_found | |$line=~m/^$split_on\s*$/g;
}
};
关闭$fh_输出文件;
是否有任何东西显示引用作品的结尾?或者任何显示下一篇文章开头的内容?如果没有,你需要给出更多被引用作品的例子,这样就可以导出模式。每个被引用的作品都在以句号结尾的单独一行上,但是每个文本都在一个单独的文件中,所以我不知道这是否有区别。使用ms
标志,它会让你在一个组中引用所有的作品,然后运行另一个正则表达式来拆分这些作品。回答得很好。注意:假设(对于sed)文件名(\&
)中没有通常情况下的特殊字符。