Търсене на подниз с фиксиран край

Бих искал да търся подниз, който завършва след определена фраза в колекция (посочена в колона на Excel) от други низове.

Да кажем, че искам да търся низа „BLUE MOON“ в други низове и искам да определя, че поднизът завършва след „N“ на „BLUE MOON“, за да избегна резултата TRUE в случай на напр. "СИНЯ ЛУННА СВЕТЛИНА". С други думи, това, от което се нуждая, е търсене на всякакви части от дума, но само отляво. Отдясно трябва да има фиксирана рамка, тоест нула допълнителни знаци. От друга страна, имам нужда от положителни резултати, ако началото е различно, например "DARK BLUE MOON" трябва да доведе до TRUE. Следователно пълното равенство не е опция.

Бих искал да използвам Find, но смятам, че не е възможно. Findизглежда не приема никакви заместващи знаци освен *.

Ето няколко думи, които можете да тествате:

  1. Очаква се положителен резултат от търсенето:

    BLUE MOON
    DARK BLUE MOON
    LIGHT BLUE MOON
    
  2. Очаква се отрицателен резултат от търсенето::

    BLUE MOONLIGHT
    LAST BLUE MOONSHINE
    BLUE MOONDANCE
    

Всички съвети също се оценяват. В момента използвам следната функция за изтриване на думи (работи добре, освен че изтрива и споменатите по-рано случаи с отрицателен очакван резултат от търсенето):

Sub testingXXX()

Dim ws As Worksheet
Set ws = ActiveWorkbook.ActiveSheet

Dim aCell As Range, bCell As Range, aSave As String, y As Long

MyAr = Split("*BLUE MOON", ",")

 For y = LBound(MyAr) To UBound(MyAr)
      With ws
         Set aCell = .Columns(1).Find(what:=MyAr(y), LookIn:=xlValues, _
                          lookat:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
                          MatchCase:=False, SearchFormat:=False)

         If Not aCell Is Nothing Then
             aSave = aCell.Address
             Do
                 If bCell Is Nothing Then
                     Set bCell = .Range("A" & aCell.row)
                 Else
                     Set bCell = Union(bCell, .Range("A" & aCell.row))
                 End If

                 Set aCell = .Columns(1).FindNext(after:=aCell)

             Loop Until aCell.Address = aSave
         End If

         Set aCell = Nothing
     End With

 Next y

 If Not bCell Is Nothing Then bCell.EntireRow.Delete

End Sub

person EDC    schedule 11.08.2015    source източник


Отговори (1)


Ето защо са измислени регулярните изрази. Ако използвате \b, за да укажете граница на думата, само точната фраза "BLUE MOON" ще бъде съпоставена, без да се допускат допълнителни знаци. Следното ще съответства на низове, съдържащи "BLUE MOON" навсякъде в рамките на:

Const PHRASES As String = "BLUE MOON,DARK BLUE MOON,LIGHT BLUE MOON,BLUE MOONLIGHT,LAST BLUE MOONSHINE,BLUE MOONDANCE"

Dim re
Set re = CreateObject("VBScript.RegExp")
re.Pattern = "\bBLUE MOON\b"

Dim w
For Each w In Split(PHRASES, ",")

    If re.Test(w) Then
        Debug.Print w & " = Match"
    Else
        Debug.Print w & " = No match"
    End If

Next

Изход (подравнен за четливост):

BLUE MOON           = Match
DARK BLUE MOON      = Match
LIGHT BLUE MOON     = Match
BLUE MOONLIGHT      = No match
LAST BLUE MOONSHINE = No match
BLUE MOONDANCE      = No match

Ако искате да сте сигурни, че низът завършва след "MOON" без абсолютно нищо допълнително, вместо това включете котвата в края на низа ($) във вашия шаблон:

re.Pattern = "\bBLUE MOON$"
person Bond    schedule 11.08.2015
comment
точно това търсех. Не знаех, че съществуват регулярни изрази :) Благодаря ви, господине! - person EDC; 11.08.2015
comment
1 кратък последващ въпрос: Ако използвам \b в началото, работи добре, например правилно съвпадение на ТЪМНО СИНЯ ЛУНА; но също така съвпада с DARK.BLUE MOON. Има ли начин да се определи произволен модел, последван от интервал, последван от СИНЯ ЛУНА? Направих някои тестове въз основа на stackoverflow.com/questions/22542834, но досега не работи - person EDC; 12.08.2015
comment
вярно . се счита за граница на думата. Ако искате да съпоставите само случаите, когато има интервал преди BLUE или това е началото на низа, можете да използвате следния образец: (^|\s)BLUE MOON\b. Вижте regex101 тук. - person Bond; 12.08.2015