2012-08-08 113 views
2

我向你保证,我已经在网站上搜索了大约两个小时。我发现应该已经工作,但他们没有。Perl,删除前三个字符后的所有内容

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

我应该说,我一直在写的一切都假设\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为好。当我试图将这些工作纳入基准工作时,我有了整数。

+3

'\ S \ S \ S \ S \ S'确实会匹配'2 3 0';然而,方括号表示[字符类](http://www.regular-expressions.info/charclass.html),所以'[\ S \ s \ S \ s \ S]'只会匹配一个字符,提供该字符是空格('\ S')或非空格('\ s')。所以'/^.*?[\ S \ s \ S \ s \ S]。{5} // s;'等价于s /^.* ?. {6} // s;', (因为'。*?'将尽可能少地匹配,在这种情况下它们总是空字符串)等同于s/^ {6} // s;' - 删除前六个字符,提供的字符串*至少包含六个字符。 – ruakh 2012-08-08 17:55:45

+0

@ruakh感谢您链接到角色类页面。我原本刚刚在括号内有一个Character和一个空格来测试它是否工作,然后在不重新测试的情况下对其进行扩展。 – 2012-08-08 18:20:37

+0

为了让事情更清楚:您的输入是否由唯一的数字组成,总是用空格分隔? – pavel 2012-08-08 18:49:46

回答

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+,就像您一样。

另一种使用后视的方法是s/(?<=^\d \d \d).*//s。换句话说,删除前面有^\d \d \d的任何字符 - 字符串的开始,后跟三个空格分隔的数字。这种方法没有真正的优势 - 我可能以另一种方式来做 - 但是既然你提到了后顾之忧,下面就是你如何做到这一点。 (再次,像s/(?<=^\S\s\S\s\S).*//s这样的东西更一般。)

+0

非常感谢。你的解决方案是我最终使用的,只需要用S代替d,这样我就可以得到小数,E就可以形成答案。 's/^(\ S + \ S + \ S +)。*/$ 1/s' – 2012-08-08 18:20:55

+0

很高兴能帮到你!如果这个答案解决了你的问题,你可以通过点击旁边的绿色复选标记来“接受”它。 ([关于如何提问的FAQ条目](http://stackoverflow.com/faq/#howtoask)解释了这是什么。) – 2012-08-08 19:22:51

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原来的规范所做的更改。)

+0

'/ [^ \ d] *((\ d + \ s +){3})。+ /' – gaussblurinc 2012-08-08 18:03:43

+0

当前写入负数和负指数时失败。 – Mark 2012-08-08 18:51:44

+0

我没有看到OP在哪里提到负指数或负数的可能性。但你是对的。在某些时候,仅使用Regexp :: Common即可使用社区测试解决方案。 – DavidO 2012-08-08 19:00:18

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

+0

由于这是我第一次回答问题,因此对此特定答​​案进行反对投票的解释会很有帮助。 – 2012-08-08 18:27:04

+0

你测试了你的解决方案吗? 's/^ s + \ s + \ s + \ S +]。* $/$ 1 /'是错误的,因为'[']字符类括号,并且因为没有捕获parens答案呼吁注意但没有解决)。 – DavidO 2012-08-08 18:30:30

+0

啊,我明白了。我完全错误地认为那部分是我的错。我会解决它。谢谢:D – 2012-08-08 18:39:03

1

的问题是,为什么ü想要做这样的事情与正则表达式?它似乎更容易我:

substr $string, 5; 

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

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

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

相关问题