我有一个从文本文件中读取的字符串,但在Ubuntu Linux中,我尝试从最后删除它的换行符.
我用过所有的方式.但是s/\n|\r/-/
(我看它是否发现任何替换任何新的行字符串)它替换了字符串,但是当我打印它时它仍然会进入下一行.而且,当我使用chomp
or时chop
,字符串被完全删除.我找不到任何其他解决方案.我该如何解决这个问题?
use strict;
use warnings;
use v5.12;
use utf8;
use encoding "utf-8";
open(MYINPUTFILE, "<:encoding(UTF-8)", "file.txt");
my @strings;
my @fileNames;
my @erroredFileNames;
my $delimiter;
my $extensions;
my $id;
my $surname;
my $name;
while (<MYINPUTFILE>)
{
my ($line) = $_;
my ($line2) = $_;
if ($line !~ /^(((\X|[^\W_ ])+)(.docx)(\n|\r))/g) {
#chop($line2);
$line2 =~ s/^\n+//;
print $line2 . " WRONG FORMAT!\n";
}
else {
#print "INSERTED:".$13."\n";
my($id) = $13;
my($name) = $2;
print $name . "\t" . $id . "\n";
unshift(@fileNames, $line2);
unshift(@strings, $line2 =~ /[^\W_]+/g);
}
}
close(MYINPUTFILE);
Run Code Online (Sandbox Code Playgroud)
tch*_*ist 17
删除Unicode换行字形(包括CRLF对)的正确方法是使用\R
v5.10中引入的正则表达式字符.
该use encoding
编译指示被强烈弃用.您应该使用use open
pragma,或者在3-arg的mode参数中使用编码open
,或者使用binmode
.
use v5.10; # minimal Perl version for \R support
use utf8; # source is in UTF-8
use warnings qw(FATAL utf8); # encoding errors raise exceptions
use open qw(:utf8 :std); # default open mode, `backticks`, and std{in,out,err} are in UTF-8
while (<>) {
s/\R\z//;
...
}
Run Code Online (Sandbox Code Playgroud)
TLP*_*TLP 10
您可能遇到一个以Windows文件结尾的行导致问题.例如,诸如"foo bar \n"之类的字符串实际上将是"foo bar\r \n".chomp
在Ubuntu上使用时,您将删除变量中$/
包含的任何内容,即"\n".那么,剩下的就是"foo bar\r \n".
这是一个微妙但非常常见的错误.例如,如果您打印"foo bar\r \n"并添加换行符,则不会发现错误:
my $var = "foo bar\r\n";
chomp $var;
print "$var\n"; # Remove and put back newline
Run Code Online (Sandbox Code Playgroud)
但是当您将字符串与另一个字符串连接时,您将覆盖第一个字符串,因为\r
将输出句柄移动到字符串的开头.例如:
print "$var: WRONG\n";
Run Code Online (Sandbox Code Playgroud)
它实际上是"foo bar\r \n:WRONG \n",但后面的文本\r
会导致以下文本回到第一部分的顶部:
foo bar\r # \r resets position
: WRONG\n # Second line prints and overwrites
Run Code Online (Sandbox Code Playgroud)
当第一行比第二行长时,这更明显.例如,尝试以下操作:
perl -we 'print "foo bar\rbaz\n"'
Run Code Online (Sandbox Code Playgroud)
你会得到输出:
baz bar
Run Code Online (Sandbox Code Playgroud)
解决方案是删除坏线结尾.您可以使用该dos2unix
命令执行此操作,也可以直接在Perl中执行以下操作:
$line =~ s/[\r\n]+$//;
Run Code Online (Sandbox Code Playgroud)
此外,请注意您的其他代码有点可怕.例如你认为$13
包含什么?这是你前一个正则表达式中第13个括号所捕获的字符串.我很确定该值始终未定义,因为您没有13个括号.
你宣布两套$id
和$name
.一个在循环外面,一个在顶部.这是非常糟糕的做法,IMO.只在他们需要的范围内声明变量,并且永远不要将所有声明都放在脚本的顶部,除非您明确要求它们对文件是全局的.
为什么使用$line
和$line2
何时具有相同的价值?只是用$line
.
而且严重的是,这是怎么回事:
if ($line !~ /^(((\X|[^\W_ ])+)(.docx)(\n|\r))/g) {
Run Code Online (Sandbox Code Playgroud)
这看起来像是试图混淆,没有冒犯.三个嵌套的否定和一堆不必要的括号?
首先,因为它是一个if-else,只需交换它并反转正则表达式.其次,[^\W_]
双重否定是相当混乱的.为什么不用[A-Za-z0-9]
?您可以拆分它以便更容易解析:
if ($line =~ /^(.+)(\.docx)\s*$/) {
my $pre = $1;
my $ext = $2;
Run Code Online (Sandbox Code Playgroud)
您可以使用以下内容擦除换行符:
$line =~ s/[\n\r]//g;
Run Code Online (Sandbox Code Playgroud)
但是,当您这样做时,您需要更改if
语句中的正则表达式而不是查找它们.我也并不认为你想/g
在你的if
.你真的不应该有$line2
.
我也不会做这种事情:
print $line2." WRONG FORMAT!\n";
Run Code Online (Sandbox Code Playgroud)
你可以做
print "$line2 WRONG FORMAT!\n";
Run Code Online (Sandbox Code Playgroud)
......而是.此外,print接受一个列表,因此您可以只使用逗号代替串联字符串.