Perl,删除前三个字符后的所有内容

时间:2012-08-08 17:48:31

标签: regex perl line substitution

我向你们保证,我现在已经在网站上搜索了大约两个小时。我发现有几个应该有效,但他们没有。

我有一行由空格分隔的不同数量的数字组成。我想在第三个数字后删除所有内容。

我应该说我写的所有内容都假设\S\s\S\s\S与前三个数字匹配。空格在1到2之间,以及2和3之间。

我预计以下工作:

s/^.*?[\S\s\S\s\S].{5}//s;

但它与我想要的完全相反。

我希望2 3 0 4 5 6 7 1 0 1 2成为2 3 0

我真的更愿意保持替代。我已经尝试了一个人提到的后视,我没有运气。在我尝试这些命令之前,我应该将前3个数字保存为字符串吗?

编辑:

我应该澄清一下,这些数字也可以是1.57或1.00E01的形式。当我试图将其用于基线工作时,我有整数。

4 个答案:

答案 0 :(得分:5)

\S\s\S\s\S确实匹配由空格字符分隔的三个非空格字符。但是,^.*?[\S\s\S\s\S].{5}做了一些完全不同的事情:

  • ^匹配该行的开头。
  • .*?匹配字符,直到下一场比赛开始(尽可能多)。由于您指定了/s,因此.也会与换行符匹配。
  • [\S\s\S\s\S]是一个字符类,因此与[\S\s]相同 - 匹配\S\s,也就是说。
  • .{5}将匹配五个字符。

由于[\S\s]./s匹配相同的内容,.*?将永远不会匹配任何字符,因为它希望尽可能少地匹配。因此,这与s/^.{6}//s相同 - 从字符串中删除前六个字符。如你所见,那不是你想要的!

保留前三个数字的一​​种方法是明确匹配它们:s/^(\d \d \d).*/$1/s。在这里,\d匹配单个数字(0 - 9)与它们之间的文字空格。我们匹配前三个后跟任何东西,然后替换整个匹配 - 因为它以.*结束,这就是整个字符串 - 只是在括号之间的位,前三个数字。如果你的号码长度超过一位数,那么s/^(\d+ \d+ \d+).*/$1/s就会做你想要的;如果您可以将任意类似空格的字符(空格,制表符,换行符)分开,那么s/^(\d\s\d\s\d\s).*/$1/s就是您想要的(或\s+,如果您可以有多个空格)。如果您想要捕获除数字之外的行,您可以使用\S\S+,就像您一样。

使用lookbehind的另一种方法是s/(?<=^\d \d \d).*//s。换句话说,删除任何以^\d \d \d开头的字符 - 字符串的开头后跟三个以空格分隔的数字。这种方法没有真正的优势 - 我可能会采用另一种方式 - 但是既然你提到了后视,那么你就可以做到这一点。 (同样,像s/(?<=^\S\s\S\s\S).*//s这样的东西更为通用。)

答案 1 :(得分:1)

明确地匹配前三个数字,然后放弃其他所有数字。

s/^([\dE.]+)\s+([\dE.]+)\s+([\dE.]+).*$/$1 $2 $3/;

其工作原理如下:

$ perl -MYAPE::Regex::Explain -E 'say YAPE::Regex::Explain->new(q{^([\dE.]+)\s+([\dE.]+)\s+([\dE.]+).*$})->explain;'
The regular expression:

(?-imsx:^([\dE.]+)\s+([\dE.]+)\s+([\dE.]+).*$)

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?-imsx:                 group, but do not capture (case-sensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  ^                        the beginning of the string
----------------------------------------------------------------------
  (                        group and capture to \1:
----------------------------------------------------------------------
    [\dE.]+                  any character of: digits (0-9), 'E', '.'
                             (1 or more times (matching the most
                             amount possible))
----------------------------------------------------------------------
  )                        end of \1
----------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
----------------------------------------------------------------------
  (                        group and capture to \2:
----------------------------------------------------------------------
    [\dE.]+                  any character of: digits (0-9), 'E', '.'
                             (1 or more times (matching the most
                             amount possible))
----------------------------------------------------------------------
  )                        end of \2
----------------------------------------------------------------------
  \s+                      whitespace (\n, \r, \t, \f, and " ") (1 or
                           more times (matching the most amount
                           possible))
----------------------------------------------------------------------
  (                        group and capture to \3:
----------------------------------------------------------------------
    [\dE.]+                  any character of: digits (0-9), 'E', '.'
                             (1 or more times (matching the most
                             amount possible))
----------------------------------------------------------------------
  )                        end of \3
----------------------------------------------------------------------
  .*                       any character except \n (0 or more times
                           (matching the most amount possible))
----------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

(考虑到OP对原始规范所做的更改而更新。)

答案 2 :(得分:1)

您所说的代码s/^.*?[\S\s\S\s\S].{5}//s; 我会这样写:s/^(\S\s\S\s\S).*$/$1/ 您忘记使用$ 1来捕获要保留的替换部分,并且在开头使用。*可能会导致删除起始数字而不是尾随数字。 此外,我不确定您是否保证单个数字或单个空白字符,因此您可以使用s/^(\S+\s+\S+\s+\S+).*$/$1/编写代码来捕获所有空格和所有数字。 如果我需要澄清一点,请告诉我。

这是一个我认为对Perl正则表达式非常有帮助的网站:http://pubcrawler.org/perl-reference.html

答案 3 :(得分:1)

问题是,为什么你想用regexp做这样的事情?对我而言似乎更容易:

substr $string, 5;

或者如果你真的想(我没有测试):

s/^(.{5})(.*)/$1/

括号允许你“记住”模式,这就是说你想要用模式的第一部分(前五个字符)替换几乎所有东西的方式。这个模式将匹配任何文本行,只留下前5个字符,你可能想要修改它以匹配3个数字,它们之间有空格