我向你们保证,我现在已经在网站上搜索了大约两个小时。我发现有几个应该有效,但他们没有。
我有一行由空格分隔的不同数量的数字组成。我想在第三个数字后删除所有内容。
我应该说我写的所有内容都假设\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的形式。当我试图将其用于基线工作时,我有整数。
答案 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个数字,它们之间有空格