我正在研究一个带有大约3k文本文档的文献计量学项目,我正在试图弄清楚如何从非结构化文本到引用列表。格式变化很大,但它们都以Works引用结束。到目前为止,我已经想出了这个:
sed -n '/Works Cited/,$p' Jones.txt > newfile.txt
在所有〜3k文件上运行后,我将它们全部合并进行分析。但是知道哪些行/引用来自哪个文档是有意义的。所以我最好的猜测是涉及两个步骤:
例如,对于名为Jones.txt的文档:
... Vivamus fringilla dapibus volutpat。 Phasellus nec mattis orci,vitae ornare> tellus。 Nunc at porta libero。 Cras non ipsum id justo auctor ullamcorper。 Lorem> ipsum dolor sit amet,consectetur adipiscing elit。 Phasellus nec nulla tincidunt,> venenatis nisi a,pharetra neque。 Morbi euismod id mauris vitae imperdiet。 Nam> sagittis mattis urna vel consectetur。 sagittis整体rhoncus leo> sollicitudin。
作品引用
琼斯,特德。生物学。纽约:Penguin,2009年。 史密斯,玛丽。 “蝴蝶与生物学。” Journal 21.2(2013):1-10。
我想制作这个:
Jones.txt,Jones,Ted。生物学。纽约:Penguin,2009年。 Jones.txt,史密斯,玛丽。 “蝴蝶与生物学。” Journal 21.2(2013):1-10。
这可能吗?有没有更好的方式来考虑它?我试着去搜索SO和其他地方寻求解决方案,但也许我不是在寻找合适的短语。这对sed,perl等最好吗?解决方案是否会更改为运行* .txt而不仅仅是Jones.txt?
非常感谢任何和所有帮助。
-JCC
答案 0 :(得分:3)
awk
您没有提及您的操作系统,但假设您可以访问GNU awk
,请尝试:
$ 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.
请注意,在此解决方案中,您可以在上面的示例中通过*.txt
一次在命令行上指定所有文件名,GNU awk
更新变量FILENAME
因为它从一个文件切换到下一个文件。
工作原理:
FNR==1{f=0}
在每个文件的第一行,将标记f
设置为零,表示我们尚未看到此文件的Works Cited
行。
f && /./{printf "%s, ", FILENAME}
如果标志f
非零(意味着已经看到Works Cited
)并且该行是非空的(行上至少有一个字符),则打印文件名接着是逗号和空格。
f{print}
如果标志f
非零,请打印整行。
/Works Cited/{f=1}
如果此行包含Works Cited
,请将标记f
设置为1。
FILENAME
变量是GNU扩展名。
awk
对于不支持awk
的{{1}}版本,我们可以使用shell循环,依次将FILENAME
变量awk
设置为每个文件的名称:
name
for f in *.txt
do
awk -v name="$f" 'f && /./{printf name ", "} f{print} /Works Cited/{f=1}' "$f"
done
如果您真的必须使用sed
,请尝试:
sed
如果您确定您的文件名不包含任何sed-active字符,则可以接受此方法。
答案 1 :(得分:3)
您可以使用简单的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;