2

我向你们保证,我已经在该网站上搜索了大约两个小时。我找到了几个应该有效的方法,但它们没有。

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

我应该说,我一直在写的所有内容都假设这\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

4 回答 4

5

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

  • ^匹配行的开头。
  • .*?匹配字符直到下一个匹配可以开始(不是尽可能多)。由于您指定/s,.也将匹配换行符。
  • [\S\s\S\s\S]是一个字符类,因此与[\S\s]—match any \Sor相同\s,也就是说任何东西。
  • .{5}将匹配五个字符。

因为[\S\s].with/s匹配相同的东西,所以.*?永远不会匹配任何字符,因为它想尽可能少地匹配。因此,这与s/^.{6}//s从字符串中删除前六个字符相同。如您所见,这不是您想要的!

保留前三个数字的一​​种方法是显式匹配它们:s/^(\d \d \d).*/$1/s. 在这里,\d匹配单个数字 ( 0–<code>9),它们之间有文字空格。我们匹配前三个后面的任何内容,然后替换整个匹配项——因为它以 结尾.*,这就是整个字符串——只用括号之间的位,前三个数字。如果您的号码可以超过一位数,那么s/^(\d+ \d+ \d+).*/$1/s您可以随心所欲;如果您可以使用任意类似空格的字符(空格、制表符、换行符)分隔它们,那么s/^(\d\s\d\s\d\s).*/$1/s这就是您想要的(或者\s+如果您可以有多个空格)。如果您想捕捉包含数字以外的内容的行,您可以使用\Sor \S+,就像以前一样。

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

于 2012-08-08T18:05:58.510 回答
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 对原始规范所做的更改进行了更新。)

于 2012-08-08T17:58:49.040 回答
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

于 2012-08-08T18:02:35.810 回答
1

问题是,你为什么要用正则表达式做这样的事情?对我来说似乎更容易:

substr $string, 5;

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

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

括号允许您“记住”模式,这就是说您想用模式的第一部分(前五个字符)替换几乎所有内容的方式。此模式将匹配任何文本行并仅保留前 5 个字符也许您想修改它以匹配 3 个数字,它们之间有空格

于 2012-08-08T18:03:12.797 回答