【问题标题】:Is there a better way to add/remove 'B's from my string in Perl?有没有更好的方法在 Perl 中从我的字符串中添加/删除“B”?
【发布时间】:2011-11-28 11:37:30
【问题描述】:

多行文字

某些行具有以下模式/^aaa(B+)(.*)/

  • 以“aaa”开头
  • 后跟数字“B”(1 到 9)
  • 剩余的行

需要构造一个函数得到什么:

  • 标量中的文本,以及
  • shifting参数如何移动B的数量

例如:

change_ab(2,$text)  # and the function will add 2 B
change_ab(-1, $text) #the function will remove one B

编辑:添加了一些示例 - (结果需要有 min 1B 或 max 9Bs) - 在我的源代码中是这些条件,但我忘了在这里写(sry))

 shifting   from     result
    2       aaaB     aaaBBB
    3       aaaBB    aaaBBBBB
   -2       aaaBBBB  aaaBB
   -3       aaaBB    aaaB          #min.1
    9       aaaBBBB  aaaBBBBBBBBB  #max.9    

我的解决方案是将标量文本分成几行。不是很优雅。 :(

存在一些更好/更快的解决方案 - 比如一个不需要拆分的大正则表达式?

这是我的代码:

use 5.014;
use warnings;

my $mytext = "some text
aaaB some another text
text3 here
aaaBB some text4
another textxxx
aaaBBBBXX some text4
another textzzzz
";

say change_ab(-1,$mytext);

sub change_ab {
    my($bshift, $text) = @_;

    my $out = "";
    foreach my $line ( split(/[\r\n]/, $text) ) {
        if( $line =~ /^aaa(B+)(.*)/) {
            my $bcnt = length($1);    
            my $wantedBcnt = $bcnt + $bshift;
            $wantedBcnt = 1 if $wantedBcnt < 1;
            $wantedBcnt = 9 if $wantedBcnt > 9;
            my $wantedBstr = sprintf("aaa%s", "B" x $wantedBcnt);

            $line =~ s/^aaaB+/$wantedBstr/;
        }
        $out .= $line . "\n";
    }
    return($out);
}

基于 Zaid 回答的新版本:

use 5.014;
use warnings;

my $mytext = "some text
aaaB some another text
text3 here
aaaBB some text4
another textxxx
aaaBBBBXX some text4
another textzzzz
";

say change_ab(8, $mytext);

sub change_ab {
    $_[1] =~ s{(?<=^aaa)(B+)}{ 'B' x fixshift(length($1)+$_[0]) }gem;
    return $_[1];
}

sub fixshift {
    return 9 if $_[0] > 9;
    return 1 if $_[0] < 1;
    return $_[0];
}

Ps:如果有人可以给出更好的问题标题 - 请。改变它。

【问题讨论】:

  • 天啊-我的错-我忘了写下来,结果我需要至少 1B 或最多 9B。我在我的源代码中有这些检查 - 但不幸的是我忘了把它写到文本中......我得到的所有解决方案都是从“aaaB”制作的,只有“aaa”。我的错。 ;(
  • 而不是fixshift,我想说有足够的调整来证明使用辅助变量是合理的:s{...}{ my $reps = length($1) + $_[0]; 'B' x $reps &lt; 1 ? 1 : $reps &gt; 9 ? 9 : $reps }。现在看来,您似乎需要重新审视大局,以了解为什么首先需要进行如此复杂的操作。
  • 简单地说,输入已经定义了格式——来自一个更大的系统,所以不能改变它。输出格式必须与输入相同(将替换它)。我需要改变'B'的数量。就这样。你的解决方案很棒。谢谢。 :)

标签: perl


【解决方案1】:

/e 修饰符为您完成繁重的工作:

$mytext =~ s{(?<=^aaa)([bB]+)}{ 'B' x (length($1) + $b_shift) }gem;

如果 $b_shift 预计会发生变化,请将操作包装在单个子中:

sub change_ab {

    my $b_shift = +shift ;   # $_[0] = b_shift,  $_[1] = text

                             # After shift, $_[0] is text

    $_[0] =~ s{(?<=^aaa)([bB]+)}{ 'B' x (length($1) + $b_shift) }gem;

    return $_[0];  # Explicit return avoids scalar context interpolation
}

用法

my $mytext = 
"some text
aaaB some another text
text3 here
aaaBB some text4
another textxxx
aaaBBBBXX some text4
another textzzzz
";

change_ab ( -1, $mytext );  

print $mytext;

输出

some text
aaa some another text
text3 here
aaaB some text4
another textxxx
aaaBBBXX some text4
another textzzzz

【讨论】:

  • 首先测试了这个,因为它真的很好很短!但结果我必须至少得到一个 B,所以当转换为负数时,我应该从 aaaB 得到“aaaB”,而不仅仅是“aaa”。而在另一边,当从“aaaBBBB”移动 +7 时,我应该得到最多 9 个 B,而不是 11 (aaaBBBBBBBBB)
  • 接受了这个 - 因为给了我一个新的想法如何重做我的脚本......;)thanx。
  • @jm666 :我相信你可以调整这个想法来限制你的“B”重复,尽管让这成为一个教训;您得到的答案与您提出的问题一样好。
【解决方案2】:

这也应该做的工作:

#!/usr/bin/perl

use strict;
use warnings;
use 5.10.1;

sub change_ab {
   my ($shift, $string) = @_;

   while ($string =~ m/[^#](aaaB+)/m) {
      my $numB = length($1)-3; # account for 'aaa' by '-3'

      # if the new number of 'B's would be negative, just keep
      # the old number; 0 'B's is allowed though (otherwise change
      # '>= 0' to '> 0')
      my $new_numB = ($numB + $shift >= 0) ? $numB + $shift : $numB;

      # add '#' to mark this instance of aaaB+ as modified already
      my $replacement = sprintf "#aaa%s", 'B' x $new_numB;

      # replace the FIRST non-modified instance of aaaB+, i.e. the
      # one we've just been working on
      $string =~ s/(?<=[^#])aaaB+/$replacement/;
   }

   $string =~ s/#(aaaB*)/$1/g; # remove the '#' markers
   return $string;
}

my $mytext = "some text
aaaB some another text
text3 here
aaaBB some text4
another textxxx
aaaBBBBXX some text4
another textzzzz
";

say change_ab(-1, $mytext);

去掉一个'B'后的输出,如上面的代码,如下:

some text
aaa some another text
text3 here
aaaB some text4
another textxxx
aaaBBBXX some text4
another textzzzz

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-08
    • 1970-01-01
    • 2016-11-28
    • 2011-11-15
    • 2023-01-25
    • 1970-01-01
    • 2012-10-31
    • 2019-05-28
    相关资源
    最近更新 更多