【问题标题】:Removing newline character from a string in Perl从 Perl 中的字符串中删除换行符
【发布时间】:2012-03-17 15:22:17
【问题描述】:

我有一个从文本文件中读取的字符串,但在 Ubuntu Linux 中,我尝试从末尾删除它的换行符。

我用过所有的方法。但是对于s/\n|\r/-/(我看看它是否找到任何替换任何新行字符串)它会替换字符串,但是当我打印它时它仍然会转到下一行。此外,当我使用chompchop 时,字符串被完全删除。我找不到任何其他解决方案。我该如何解决这个问题?

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

【问题讨论】:

  • @TLP 请不要假装 Perl 字符类有 ASCII 定义,因为这在 Perl 中是完全错误的。你必须使用the definitions from UTS#18 Annex C
  • @TLP 是的,当然不是。 \w 等于 [\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}]。这是众所周知的。它涵盖了截至 Unicode v6.0 的 102,724 个代码点,比您提到的不足 63 个多 四个数量级

标签: regex string perl


【解决方案1】:

删除 Unicode 换行字素(包括 CRLF 对)的正确方法是使用 v5.10 中引入的 \R 正则表达式元字符。

强烈反对使用use encoding 杂注。您应该使用 use open pragma,或者在 3-arg 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//;
     ...
 }

【讨论】:

  • @stackoverflow 前提是您执行$data =~ s/\R//g 可以工作;注意我删除了\z 边界。不知道你为什么要去掉所有的换行符。
  • $/=undef; $data=&lt;MYINPUTFILE&gt;; data=~s/\R//g; ..怎么样?
  • @stackoverflow 当然可以。
【解决方案2】:

您可能遇到以 Windows 文件结尾的行导致问题。例如,诸如“foo bar\n”之类的字符串实际上是“foo bar\r\n”。在 Ubuntu 上使用 chomp 时,您将删除 the variable $/ 中包含的所有内容,即“\n”。所以,剩下的就是“foo bar\r”了。

这是一个微妙但非常常见的错误。例如,如果您打印“foo bar\r”并添加换行符,您将不会注意到错误:

my $var = "foo bar\r\n";
chomp $var;
print "$var\n";  # Remove and put back newline

但是,当您将字符串与另一个字符串连接时,您会覆盖第一个字符串,因为\r 将输出句柄移动到字符串的开头。例如:

print "$var: WRONG\n";

它实际上是“foo bar\r: WRONG\n”,但\r 之后的文本会导致以下文本回绕到第一部分的顶部:

foo bar\r           # \r resets position
 : WRONG\n          # Second line prints and overwrites

当第一行比第二行长时,这一点更为明显。例如,尝试以下操作:

perl -we 'print "foo bar\rbaz\n"'

你会得到输出:

baz bar

解决方案是删除坏的行尾。您可以使用dos2unix 命令执行此操作,或直接在 Perl 中使用:

$line =~ s/[\r\n]+$//;

另外,请注意您的其他代码有些可怕。例如,您认为$13 包含什么?那将是您之前的正则表达式中第 13 个括号捕获的字符串。我相当确定该值将始终未定义,因为您没有 13 个括号。

您声明了两组$id$name。一个在循环外,一个在顶部。这是非常糟糕的做法,IMO。只在它们需要的范围内声明变量,永远不要将所有声明都放在脚本的顶部,除非您明确希望它们对文件是全局的。

$line$line2 具有相同的值时,为什么要使用它们?只需使用$line

说真的,这是怎么回事:

if ($line !~ /^(((\X|[^\W_ ])+)(.docx)(\n|\r))/g) {

这看起来像是试图混淆,没有冒犯。三个嵌套的否定和一堆不必要的括号?

首先,因为它是一个 if-else,所以只需交换它并反转正则表达式。其次,[^\W_] 双重否定相当令人困惑。为什么不直接使用[A-Za-z0-9]?您可以将其拆分以使其更易于解析:

if ($line =~ /^(.+)(\.docx)\s*$/) {
    my $pre = $1;
    my $ext = $2;

【讨论】:

    【解决方案3】:

    你可以用这样的方式擦除换行符:

    $line =~ s/[\n\r]//g;
    

    但是,当您这样做时,您需要更改 if 语句中的正则表达式以不查找它们。我也不认为您想要在您的if 中添加/g。你真的不应该有$line2

    我也不会做这种事:

    print $line2." WRONG FORMAT!\n";
    

    你可以的

    print "$line2 WRONG FORMAT!\n";
    

    ... 相反。此外,print 接受一个列表,因此您可以使用逗号代替连接字符串。

    【讨论】:

      【解决方案4】:

      你可以这样做:

      =~ tr/\n//

      但实际上chomp 应该可以工作:

      while (<filehandle>){
         chomp;
         ...
      }
      

      同样s/\n|\r// 仅替换\r\n 的第一次出现。如果你想替换所有出现的地方,你需要在末尾添加全局修饰符s/\r|\n//g

      注意:如果您在 windows 中包含\r,它通常以\r\n 结束它的行,因此您希望将两者都替换(例如s/(?:\r\n|\n)//),当然上面的语句(s/\r|\n//g)用无论如何,全局修饰符都会解决这个问题。

      【讨论】:

        【解决方案5】:
        $variable = join('',split(/\n/,$variable))
        

        【讨论】:

          猜你喜欢
          • 2011-10-13
          • 1970-01-01
          • 2015-01-05
          • 1970-01-01
          • 2016-02-11
          • 1970-01-01
          • 1970-01-01
          • 2012-10-29
          相关资源
          最近更新 更多