2015-07-16 30 views
5

diyorum, dizeleri bir dizi var düşünün sıra. Dolayısıyla, ben türden bir kural formüle edebilmek istiyorum:belirlenmesi dizeleri

Match the string if, and only if, 
marker X occurs in the first/middle/last third of the string 

Örneğin, ben ilk üçte birlik bir A sahip dizeleri eşleştirmek isteyebilirsiniz. Yukarıdaki dizileri dikkate alarak, #1 ve #2 ile eşleşir. Son üçte bir A olan dizeleri de eşleştirmek istiyorum. Bu, #2 ve #3 ile eşleşir.

Girdi olarak bu türden çeşitli kuralları uygulayabilen ve sonra uygun alt dizelerle eşleşen bir genel kod/regex deseni nasıl yazabilirim?

+0

Normal ifadelerle çözülecek bir şey gibi gelmiyor. Giriş dizesinde çalışan işlevlerle kural tanımlamak daha esnektir. – nhahtdh

+1

@nhahtdh: Muhtemelen hem işlevlere hem de normal ifadelere ihtiyaç duyar (çünkü eşleşmesini istediğim şey, basit bir olsa bile bir normal ifadeyle tanımlanmalıdır). – histelheim

+0

Dizeler her zaman aynı sabit uzunlukta mı? – rloth

cevap

5

tam vektörleşen girişimi (ayarlarda oynayabilir ve eklemek istiyorsanız bana söyleyebilir/değişim şey) var üzerinde

StriDetect <- function(x, seg = 1L, pat = "A", frac = 3L, fixed = TRUE, values = FALSE){ 
    xsub <- gsub("-", "", x, fixed = TRUE) 
    sizes <- nchar(xsub)/frac 
    subs <- substr(xsub, sizes * (seg - 1L) + 1L, sizes * seg) 
    if(isTRUE(values)) x[grep(pat, subs, fixed = fixed)] else grep(pat, subs, fixed = fixed) 
} 

Test senin vektör

x <- c("A-B-B-C-C", "A-A-A-A-A-A-A", "B-B-B-C-A-A") 
StriDetect(x, 1L, "A") 
## [1] 1 2 
StriDetect(x, 3L, "A") 
## [1] 2 3 

Yoksa gerçek eşleşti dizeleri istiyorsanız

StriDetect(x, 1L, "A", values = TRUE) 
## [1] "A-B-B-C-C"  "A-A-A-A-A-A-A" 
StriDetect(x, 3L, "A", values = TRUE) 
## [1] "A-A-A-A-A-A-A" "B-B-B-C-A-A" 

dize boyutu (örneğin nchar(x) == 10) 3 ile tam olarak böler vermediğinde lütfen unutmayın, varsayılan olarak son üçüncü olan en büyük grup (örneğin boyut 4 eğer nchar(x) == 10)

1

İşte bir seçenek: Burada

f <- function(txts, needle, operator, threshold) { 
    require(stringi) 
    txts <- gsub("-", "", txts, fixed = TRUE)    # delete '-'s 
    matches <- stri_locate_all_fixed(txts, needle)  # find matches 
    ends <- lapply(matches, function(x) x[, "end"])  # extract endposition of matches (= start) 
    ends <- mapply("/", ends, sapply(txts, nchar) + 1) # divide by string length+1 
    which(sapply(mapply(operator, ends, threshold), any)) # return indices of matches that fulfill restriction of operator and its threshold 
} 
txts <- c("A-A-B-B-C-C", "A-A-A-A-A-A", "B-B-B-C-A-A") 
idx <- f(txts, needle = "A", operator = "<=", threshold = .333) 
txts[idx] 
# [1] "A-A-B-B-C-C" "A-A-A-A-A-A" 
+0

Operatör argümanının işlevini açıklar mısınız? '=>' Ve '=' burada kullanabilir miyim? – histelheim

+0

'=>' ve '==', evet. – lukeA

+0

bunu denediğimde işe yaramaz gibi görünüyor - işlevi nasıl kullanacağınızı açıklayabilir misiniz? Bazı örnekler yardımcı olabilir. – histelheim

2

İstenen gereksinimleri karşılamak için normal ifadeler oluşturan bir çözüm. Not ifadeleri sayılabilir, ancak toplam dizgeye göre sayılmaz. Bu nedenle, her bir girdi dizesi için uzunluğuna bağlı olarak özel bir regex oluşturur. Sonuncusu desen teriminde değil, grep yerine stringi::stri_detect_regex kullandım. Ayrıca, pattern bağımsız değişkenin kendisi için geçerli bir normal ifade olduğunu ve kaçması gereken herhangi bir karakterin (ör. [, .) kaçtığını da varsaydım.

library("stringi") 
strings <- c("A-B-B-C-C", "A-A-A-A-A-A-A", "B-B-B-C-A-A") 
get_regex_fn_fractions <- function(strings, pattern, which_fraction, n_groups = 3) { 
    before <- round(nchar(strings)/n_groups * (which_fraction - 1)) 
    after <- round(nchar(strings)/n_groups * (n_groups - which_fraction)) 
    sprintf("^.{%d}.*%s.*.{%d}$", before, pattern, after) 
} 
(patterns <- get_regex_thirds(strs, "A", 1)) 
#[1] "^.{0}.*A.*.{6}$" "^.{0}.*A.*.{9}$" "^.{0}.*A.*.{7}$" 

#Test regexs: 
stri_detect_regex(strings, patterns) 
#[1] TRUE TRUE FALSE