2012-11-21 167 views
4

我想知道如何使用正則表達式選擇彼此相鄰的字。 例如,我想從下面的語句選擇的數字和單詞數:R正則表達式(靠近單詞)

"140,000 mostly freeway miles" 
"173k commuter miles. "  
"154K(all highway) miles 

我不知道如何填寫在中間的可選字:

[0-9]+ ???? miles 

*附近可定義爲相隔1-3個字。感謝您指出了這一點。

+1

什麼是「近」?你想限制它們之間的字符或單詞的數量嗎?或者他們可以任意分開? –

+0

附近可能相隔1-3個字 – user1103294

+0

您使用哪種語言的正則表達式? ...爲什麼你需要選擇「英里」一詞,當你知道它永遠在那裏? – FixMaker

回答

3

以下是R的答案。其他答案可以進行一些修改。大多數情況下,他們需要「雙重逃脫」,您將不得不使用配對功能regexprregmatches

x=c("140,000 mostly freeway miles" ,"173k commuter miles. " ,"154K(all highway) miles") 


gsub('([[:digit:][:punct:]k]+).*(miles).*', 
    '\\1 \\2', 
    x, 
    ignore.case=TRUE) 

# [1] "140,000 miles" "173k miles" "154 miles"  

這就是組數字標點或組1中的k。然後是組2,這是英里這個詞,其次是其他任何內容。

你也可以用「正常」的正則表達式語法:

gsub('([0-9,k]+).*(miles).*', 
    '\\1 \\2', 
    x, 
    ignore.case=TRUE) 

不過,我會先清理數據,然後做一些簡單的匹配! (例如tolower並刪除標點符號)。

+0

這是錯過了必須有1到3個單詞之間的點。隨意複製我的正則表達式,並使其適用於R,然後我將刪除我的答案。 –

+0

我會堅持我的帖子在我的帖子的底部。如果當距離超過3個字時不應包含「英里數」,則正則表達式變得太複雜了! – Justin

0

使用這個表達式\d+([.,]\d+)?(?=.*?miles)

+0

你會如何在'R'中編寫? – Justin

+0

@Justin我想如果你使用類Perl的正則表達式,它應該馬上工作。 –

+0

第一個paren在錯誤的地方。使用'gsub(「\\ d +([。,] \\ d +)?(?=。*?miles)」,「\\ 1 \\ 2」,x,perl = TRUE)',給出'「,000大多是高速公路里程「」k個通勤里程「。你需要在R的正則表達式中加倍逃避反斜槓。 –

0

這仍然是一個有點模糊,但是我們要說,我們定義的一切作爲由空格隔開一個「字」。因此,如果有可能的話1-3,我們需要有2-4位(其實我做的第一個可選的,看到你的最後一個例子)的數量和miles之間:

\d[\d,.]*k?\s*(\S+\s+){1,3}miles 

注意你應該使這個正則表達式不區分大小寫,以匹配kK

另請注意,數字部分當然可以改進。這一個只需要第一個數字,然後包含儘可能多的數字,逗號和句點,無論是否有效的數字格式。

1

關於問題域有許多未解答的問題。這且不說,讓我們使用包含在有效匹配和否定匹配一些額外的樣本數據的問題所提供的樣本數據如下數據(我使用R version 2.14.1 (2011-12-22)):

x <- c("140,000 mostly freeway miles", "173k commuter miles. ", "154K(all highway) miles", "1,24 almost but not mostly freeway miles", "1,2,3,4K MILES") 

1,2,3,4K MILES添加爲負匹配,因爲該問題定義爲近似爲1-3 words apart,並且這具有零「接近詞」。

如果我們用下面的...

sub('[\\d,]+k?\\s+(([^\\s]+\\s+){1,3})miles', '\\1', x, ignore.case = TRUE, perl = TRUE) 

...我們得到:

[1] "mostly freeway " 
[2] "commuter . " 
[3] "154K(all highway) miles" 
[4] "1,24 almost but not mostly freeway miles" 
[5] "1,2,3,4K MILES" 

也許沒有結果你想要的。由於數據未規範化,因此您必須使用一個會變得非常複雜的正則表達式模式。如Justin建議在他的answer,clean up the data first then do some simpler matching

你可以標準化數據的一些如下:

y <- gsub('\\pP+', ' ', x, perl = TRUE) 
y <- gsub('\\s+', ' ', y, perl = TRUE) 
y <- gsub('^\\s+|\\s+$', '', y, perl = TRUE) 
y <- gsub('(\\d)\\s(?=\\d)', '\\1\\2', y, perl = TRUE) 

請參閱有關詳細信息,下面引用。這基本上是刪除標點並確保單詞由一個空格分隔。這將使你的y

[1] "140000 mostly freeway miles" 
[2] "173k commuter miles" 
[3] "154K all highway miles" 
[4] "124 almost but not mostly freeway miles" 
[5] "1234K MILES" 

現在刪除線不匹配,你在找什麼:

y <- sub('^(?!\\d+k?\\s((?!miles)[^\\s]+\\s){1,3}miles).*$', '', y, ignore.case = TRUE, perl = TRUE) 
y 
[1] "140000 mostly freeway miles" "173k commuter miles" 
[3] "154K all highway miles"  "" 
[5] "" 

最後,獲得「近話」:

y <- sub('^\\d+k?\\s((?!miles)[^\\s]+(\\s(?!miles)[^\\s]+){0,2})\\smiles', '\\1', y, ignore.case = TRUE, perl = TRUE) 
y 
[1] "mostly freeway" "commuter"  "all highway" "" 
[5] "" 

有可能更簡單的方法來標準化數據,但這給你一些正則表達式的例子來玩。

更多信息,請參見: