2013-01-31 89 views
1

我需要驗證字符矢量模式的字符串。我當前的代碼是:R代碼檢查單詞是否匹配模式

trim <- function (x) gsub("^\\s+|\\s+$", "", x) 

# valid pattern is lowercase alphabet, '.', '!', and '?' AND 
# the string length should be >= than 2 
my.pattern = c(letters, '!', '.', '?') 

check.pattern = function(word, min.size = 2) 
{ 
    word = trim(word) 
    chars = strsplit(word, NULL)[[1]] 
    all(chars %in% my.pattern) && (length(chars) >= min.size) 
} 

例子:

w.valid = 'special!' 
w.invalid = 'test-me' 

check.pattern(w.valid) #TRUE 
check.pattern(w.invalid) #FALSE 

這是很慢的我猜...有沒有更快的方式做到這一點?正則表達式可能? 謝謝! PS:謝謝大家的好回答。我的目標是建立一個29 x 29的矩陣, 其中行名和列名是允許的字符。然後我遍歷一個巨大的文本文件的每個單詞,並建立一個'字母優先'矩陣。例如,考慮單詞「特別」,從第一個字符開始:

row s, col p -> increment 1 
row p, col e -> increment 1 
row e, col c -> increment 1 
... and so on. 

我的代碼的瓶頸是在矢量分配,我是「追加」,而不是預先分配的最終載體,所以代碼需要30分鐘才能執行,而不是20秒!

+2

你可以通過包括:'word'和'min.size'來重現這一點。另外,你可以用語言解釋你開始和期望的結果。 (包括給定'word'的所需輸出。) – Justin

+0

編輯,謝謝。 – Fernando

回答

4

有一些內置函數可以清理你的代碼。我認爲你沒有充分利用正則表達式的全部力量。

這裏的問題是strsplit。當你有正則表達式時,逐字符比較事物的效率是低效的。這裏的模式使用方括號表示法篩選您想要的字符。 *用於任意數量的重複(包括零),而^$符號表示該行的開始和結束,以便除此之​​外沒有別的。 nchar(word)length(chars)相同。將&&更改爲&使向量化函數,以便您可以輸入字符串的向量並獲取邏輯向量作爲輸出。

check.pattern.2 = function(word, min.size = 2) 
{ 
    word = trim(word) 
    grepl(paste0("^[a-z!.?]*$"),word) & nchar(word) >= min.size 
} 
check.pattern.2(c(" d ","!hello ","nA!"," asdf.!"," d d ")) 
#[1] FALSE TRUE FALSE TRUE FALSE 

接下來,使用大括號一些paste0重複次數和模式可以使用min.size:

check.pattern.3 = function(word, min.size = 2) 
{ 
    word = trim(word) 
    grepl(paste0("^[a-z!.?]{",min.size,",}$"),word) 
} 
check.pattern.3(c(" d ","!hello ","nA!"," asdf.!"," d d ")) 
#[1] FALSE TRUE FALSE TRUE FALSE 

最後,你可以從trim內在的正則表達式:

check.pattern.4 = function(word, min.size = 2) 
{ 
    grepl(paste0("^\\s*[a-z!.?]{",min.size,",}\\s*$"),word) 
} 
check.pattern.4(c(" d ","!hello ","nA!"," asdf.!"," d d ")) 
#[1] FALSE TRUE FALSE TRUE FALSE 
+0

請注意,您在這裏接受像'!!'這樣的詞。 – agstudy

+1

小心'nchar(NA)' - 它是2! – hadley

+0

@agstudy符合OP的模式。 –

1

如果我理解了您所需的模式,您需要一個類似格式的正則表達式:

^\\s*[a-z!\\.\\?]{MIN,MAX}\\s*$ 

其中MIN用字符串的最小長度替換,MAX用字符串的最大長度替換。如果沒有最大長度,那麼MAX和逗號可以省略。同樣,如果沒有最大值或最小值,{}中的所有內容(包括括號本身)都可以替換爲*,表示前一項將匹配零次或多次;這相當於{0}。

這確保了在那裏任何開頭和結尾的空白後的每個字符是從一套 *小寫字母 *感嘆號(感嘆號) *問號

注意正則表達式只匹配字符串這是用Perl風格的正則表達式編寫的,因爲它是我更熟悉的;我的大部分研究是在this wiki for R text processing

您的函數緩慢的原因是將字符串拆分爲多個較小字符串的額外開銷。與正則表達式(甚至是手動遍歷字符串,比較每個字符,直到到達結尾或找到無效字符)相比,這是很多開銷。還要記住,該算法確保了O(n)的性能率,因爲分割會導致生成n個字符串。這意味着即使FAILING字符串也必須至少執行n個操作來拒絕字符串。

希望這可以澄清爲什麼你有性能問題。

+0

不錯,感謝您的鏈接! – Fernando