這是我想要做的:使用Perl,如何從兩個可能的記錄分隔符的文件中讀取記錄?
我想讀取一個文本文件到一個字符串數組。我希望字符串在文件讀入某個字符時終止(主要是;
或|
)。
例如,下面的文本
Would you; please hand me| my coat?
將放好這樣的:
$string[0] = 'Would you;';
$string[1] = ' please hand me|';
$string[2] = ' my coat?';
我能得到這樣的幫助嗎?
這是我想要做的:使用Perl,如何從兩個可能的記錄分隔符的文件中讀取記錄?
我想讀取一個文本文件到一個字符串數組。我希望字符串在文件讀入某個字符時終止(主要是;
或|
)。
例如,下面的文本
Would you; please hand me| my coat?
將放好這樣的:
$string[0] = 'Would you;';
$string[1] = ' please hand me|';
$string[2] = ' my coat?';
我能得到這樣的幫助嗎?
一種方式是注入其他字符,像\n
,只要您的特殊字符被發現,然後split在\n
:
use warnings;
use strict;
use Data::Dumper;
while (<DATA>) {
chomp;
s/([;|])/$1\n/g;
my @string = split /\n/;
print Dumper(\@string);
}
__DATA__
Would you; please hand me| my coat?
打印出:
$VAR1 = [
'Would you;',
' please hand me|',
' my coat?'
];
更新:原來的問題James提出的輸入文本顯示在單行上,如上面的__DATA__
所示。因爲這個問題格式不好,其他人編輯了這個問題,把1行分成2個。只有詹姆斯知道1行還是2行是有意的。
東西沿着
$text = <INPUTFILE>;
@string = split(/[;!]/, $text);
行應該做的伎倆更多或更少。
編輯:我已將「/;!/」更改爲「/ [;!] /」。
如果你打算這樣做,我認爲你必須使用某種形式的「啜食」文件,因爲
不要忘記執行's/\ n// g'。 – 2010-02-12 02:19:13
這完全不能像OP想要的那樣工作。試一試。它在2個字符的序列';!'上分開,這在輸入中不會出現。 – toolic 2010-02-12 02:27:12
我更喜歡@toolic's answer,因爲它很容易處理多個分隔符。
但是,如果你想過於複雜的事情,你總是可以嘗試:
#!/usr/bin/perl
use strict; use warnings;
my @contents = ('');
while (my $line = <DATA>) {
last unless $line =~ /\S/;
$line =~ s{$/}{ };
if ($line =~ /^([^|;]+[|;])(.+)$/) {
$contents[-1] .= $1;
push @contents, $2;
}
else {
$contents[-1] .= $1;
}
}
print "[$_]\n" for @contents;
__DATA__
Would you; please
hand me| my coat?
讓Perl的爲你做了一半的工作通過設置$/
(輸入記錄分隔符),以豎條,然後提取分號分隔的字段:
#!/usr/bin/perl
use warnings;
use strict;
my @string;
*ARGV = *DATA;
$/ = "|";
while (<>) {
s/\n+$//;
s/\n/ /g;
push @string => $1 while s/^(.*;)//;
push @string => $_;
}
for (my $i = 0; $i < @string; ++$i) {
print "\$string[$i] = '$string[$i]';\n";
}
__DATA__
Would you; please
hand me| my coat?
輸出:
$string[0] = 'Would you;'; $string[1] = ' please hand me|'; $string[2] = ' my coat?';
+1好的和有效的方法。 – 2010-02-12 09:56:48
這將做到這一點。在保留要分割的令牌的同時使用拆分的技巧是使用零寬度的回溯匹配:split(/(?<=[;|])/, ...)
。
注意:mctylr的答案(當前最高評分)實際上並不正確 - 它將在新行上拆分字段,b/c只能在文件的單行上一次處理。
gbacon的回答使用輸入記錄分隔符($/
)非常聰明 - 既省時又省時 - 但我不認爲我想在生產代碼中看到它。在記錄分隔符中放置一個分割標記,在分割中放入另一個分割標記,這有點不明顯(你必須用Perl來對抗...))這將使它難以維護。我也不確定他爲什麼要刪除多個換行符(我認爲你並不需要這麼做?),以及爲什麼他只是爲了'|' - 終止記錄而這樣做。
# open file for reading, die with error message if it fails
open(my $fh, '<', 'data.txt') || die $!;
# set file reading to slurp (whole file) mode (note that this affects all
# file reads in this block)
local $/ = undef;
my $string = <$fh>;
# convert all newlines into spaces, not specified but as per example output
$string =~ s/\n/ /g;
# split string on ; or |, using a zero-width lookback match (?<=) to preserve char
my (@strings) = split(/(?<=[;|])/, $string);
我的解決方案(mctylr響應)對於原始問題中提供的輸入是正確的。後來修改了這個問題,改變了輸入。在我看來,這個問題是不明確的:OP是想爲整個文件使用單個數組還是爲每個文件行使用數組?詹姆斯應該澄清。 – toolic 2010-02-12 13:34:52
糟糕,對不起,工具,你是對的 - 我的意思是你的回覆,不是mctylr的!在對輸入進行更改後,我進來了。 使用回溯匹配的一個限制是,您的代碼沒有:回溯匹配必須是恆定寬度。它在這裏工作得很好 - ;和|都只是1個字符 - 但是如果詹姆斯有一個寬度不同的標記,比如說他想分離的「//」,那麼你就是技術(用單一的標記代替不同的標記)會更好。 – curveship 2010-02-12 15:01:44
爲什麼'|'變成'!'? – 2010-02-12 02:08:21
請注意,如上所示,您還希望從輸入中刪除換行符。 – darch 2010-02-12 22:48:02