提取短语后的所有文本,然后在每行的开头添加文件名?

时间:2015-01-20 01:17:41

标签: regex perl sed

我正在研究一个带有大约3k文本文档的文献计量学项目,我正在试图弄清楚如何从非结构化文本到引用列表。格式变化很大,但它们都以Works引用结束。到目前为止,我已经想出了这个:

sed -n '/Works Cited/,$p' Jones.txt > newfile.txt

在所有〜3k文件上运行后,我将它们全部合并进行分析。但是知道哪些行/引用来自哪个文档是有意义的。所以我最好的猜测是涉及两个步骤:

  1. 提取短语Works Cited后面的行。
  2. 在每行的开头插入文件名。 (没有标准的元数据结构,甚至没有出现作者,标题等的一致行。)
  3. 例如,对于名为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

2 个答案:

答案 0 :(得分:3)

使用GNU 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扩展名。

非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;