2012-08-08 105 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個數字和它們之間的空格。

相關問題