اختبار إذا كانت الأحرف في السلسلة في R




regex string (6)

إجابة

تنهد ، استغرق الأمر 45 دقيقة للعثور على الإجابة على هذا السؤال البسيط. الجواب هو: grepl(needle, haystack, fixed=TRUE)

# Correct
> grepl("1+2", "1+2", fixed=TRUE)
[1] TRUE
> grepl("1+2", "123+456", fixed=TRUE)
[1] FALSE

# Incorrect
> grepl("1+2", "1+2")
[1] FALSE
> grepl("1+2", "123+456")
[1] TRUE

ترجمة

يتم تسمية grep بعد linux القابل للتنفيذ ، والذي هو بحد ذاته اختصار لـ " g lobal R egular E xpression P rint" ، فإنه يقرأ خطوط الإدخال ثم يطبعها إذا كانت مطابقة للحجج التي قدمتها. "Global" تعني أن المباراة يمكن أن تحدث في أي مكان على سطر الإدخال ، سأشرح "التعبير العادي" أدناه ، ولكن الفكرة هي أنها طريقة أكثر ذكاءً لمطابقة السلسلة (R يستدعي هذا "الحرف" ، على سبيل المثال class("abc") ) ، و "الطباعة" لأنه برنامج سطر الأوامر ، والإصدار الناتج يعني أنه يطبع إلى سلسلة الإخراج الخاصة به.

الآن ، برنامج grep هو في الأساس مرشح ، من خطوط الإدخال ، إلى خطوط الإنتاج. ويبدو أن وظيفة grep في R بشكل مشابه ستأخذ مجموعة من المدخلات. لأسباب غير معروفة تمامًا بالنسبة لي (بدأت فقط اللعب مع R منذ ساعة تقريبًا) ، تقوم بإرجاع متجه من الفهارس التي تطابق ، بدلاً من قائمة التطابقات.

ولكن ، مرة أخرى إلى السؤال الأصلي ، ما نريده حقًا هو معرفة ما إذا وجدنا الإبرة في كومة القش ، قيمة صواب / خطأ. من الواضح أنهم قرروا تسمية هذه الدالة grepl ، كما في "grep" ولكن مع قيمة الإرجاع " L ogical" (يسمونها قيم منطقية صحيحة وكاذبة ، مثل class(TRUE) ).

إذن ، نحن الآن نعرف من أين جاء الاسم وما يفترض أن يفعله. دعونا نعود إلى التعبيرات العادية. الحجج ، على الرغم من أنها سلاسل ، يتم استخدامها لبناء تعبيرات عادية (من الآن فصاعدا: تعبير منطقي). A regex هي طريقة لمطابقة سلسلة (إذا كان هذا التعريف يزعجك ، فليذهب). على سبيل المثال ، يتطابق التعبير العادي a مع الحرف "a" ، يتطابق regex a* مع الحرف "a" أو أكثر من مرة ، وسيتطابق regex a+ مع الحرف "a" مرة واحدة أو أكثر. وبالتالي في المثال أعلاه ، فإن الإبرة التي نبحث عنها لـ 1+2 ، عندما تعامل كمرجع معتاد ، تعني "واحد أو أكثر 1 متبوعًا بـ 2" ... لكن تتبعنا علامة زائد!

لذا ، إذا استخدمت grepl بدون تحديد fixed ، فإن grepl دون grepl ، وهذا من شأنه أن يعمل بشكل عرضي في كثير من الأحيان ، يمكننا أن نرى أنه يعمل حتى على سبيل المثال OP. ولكن هذا خطأ كامن! نحتاج أن نقول لها أن المدخلات عبارة عن سلسلة ، وليست تعبيرًا عاديًا ، والتي يبدو أنها fixed . لماذا ثابتة؟ لا يوجد دليل ، مرجعية هذه الإجابة ب / ج كنت على الأرجح أن تبحث عنه 5 مرات أكثر قبل أن تحصل عليه حفظها.

بعض الأفكار النهائية

كلما كان كودك أفضل ، كلما قل تاريخ معرفتك لفهمه. يمكن أن تحتوي كل وسيطة على قيمتين مثيرتين للاهتمام على الأقل (وإلا لن تحتاج إلى أن تكون حجة) ، فإن حجة قائمة docs 9 هنا ، مما يعني أن هناك على الأقل 2 ^ 9 = 512 طريقة لاستدعائها ، وهذا كثير من العمل الكتابة والاختبار ، وتذكر ... decouple هذه الوظائف (تقسيمها ، وإزالة التبعيات على بعضها البعض ، وأشياء سلسلة مختلفة من regex الأشياء تختلف عن أشياء ناقلات). كما أن بعض الخيارات حصرية بشكل متبادل ، لا تعطي المستخدمين طرقًا غير صحيحة لاستخدام الشفرة ، أي أن الإشكالية قد تكون غير منطقية من الناحية الهيكلية (مثل تمرير خيار غير موجود) ، وليس منطقيًا منطقيًا (حيث يجب عليك يصدر تحذير لشرح ذلك). ضع بشكل مجازي: استبدال الباب الأمامي في جانب الطابق العاشر بجدار أفضل من تعليق علامة تحذر من استخدامه ، ولكن إما أفضل من كلاهما. في الواجهة ، تحدد الدالة ما يجب أن تبدو عليه الوسيطات ، وليس المتصل (لأن المتصل يعتمد على الوظيفة ، ويستنتج كل شيء قد يرغب الجميع في الاتصال به مع جعل الوظيفة تعتمد على المتصلين أيضًا ، وهذا النوع من التبعية الدورية سرعان ما تسد النظام إلى أعلى ولا تقدم أبدا الفوائد التي تتوقعها). كن حذرا جدا من أنواع المراوغة ، إنه عيب في التصميم أن الأشياء مثل TRUE و 0 و "abc" كلها متجهات.

أحاول تحديد ما إذا كانت السلسلة مجموعة فرعية لسلسلة أخرى. فمثلا:

chars <- "test"
value <- "es"

أريد إرجاع TRUE إذا ظهرت "value" كجزء من سلسلة الأحرف "chars". في السيناريو التالي ، أرغب في إرجاع false:

chars <- "test"
value <- "et"

أيضا ، يمكن القيام به باستخدام مكتبة "stringr":

> library(stringr)
> chars <- "test"
> value <- "es"
> str_detect(chars, value)
[1] TRUE

### For multiple value case:
> value <- c("es", "l", "est", "a", "test")
> str_detect(chars, value)
[1]  TRUE FALSE  TRUE FALSE  TRUE

استخدم هذه الوظيفة من حزمة stringi :

> stri_detect_fixed("test",c("et","es"))
[1] FALSE  TRUE

بعض المعايير:

library(stringi)
set.seed(123L)
value <- stri_rand_strings(10000, ceiling(runif(10000, 1, 100))) # 10000 random ASCII strings
head(value)

chars <- "es"
library(microbenchmark)
microbenchmark(
   grepl(chars, value),
   grepl(chars, value, fixed=TRUE),
   grepl(chars, value, perl=TRUE),
   stri_detect_fixed(value, chars),
   stri_detect_regex(value, chars)
)
## Unit: milliseconds
##                               expr       min        lq    median        uq       max neval
##                grepl(chars, value) 13.682876 13.943184 14.057991 14.295423 15.443530   100
##  grepl(chars, value, fixed = TRUE)  5.071617  5.110779  5.281498  5.523421 45.243791   100
##   grepl(chars, value, perl = TRUE)  1.835558  1.873280  1.956974  2.259203  3.506741   100
##    stri_detect_fixed(value, chars)  1.191403  1.233287  1.309720  1.510677  2.821284   100
##    stri_detect_regex(value, chars)  6.043537  6.154198  6.273506  6.447714  7.884380   100

استخدم وظيفة grepl

grepl(value, chars)
# TRUE

فقط في حالة ما إذا كنت ترغب أيضًا في التحقق مما إذا كانت سلسلة (أو مجموعة من السلاسل) تحتوي على (سلاسل) سلاسل فرعية متعددة ، يمكنك أيضًا استخدام '|' بين اثنين من سلاسل فرعية.

>substring="as|at"
>string_vector=c("ass","ear","eye","heat") 
>grepl(substring,string_vector)

ستحصل

[1]  TRUE FALSE FALSE  TRUE

منذ الكلمة الأولى لديها سلسلة فرعية "كما" ، والكلمة الأخيرة تحتوي على سلسلة "في"


يمكنك استخدام grep

grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)




r-faq