2013-11-11 2 views
0

У меня есть алгоритм выделения, который берет строку и добавляет коды подсветки вокруг совпадений в ней. Проблема, с которой я сталкиваюсь, - это слова типа «Найти tæst» в качестве искомой строки и «taest» в качестве строки для поиска. Поскольку длина строки поиска не соответствует длине совпадения, я не могу точно найти конец совпадения. IndexOf в моем случае показывает мне совпадение, но поскольку комбинированный æ засчитывается как один символ, он отбрасывает мое обнаружение конца матча. Я не думаю, что IndexOf будет работать для меня здесь. Будет работать то, что возвращает индекс совпадения и длину совпадения. Но я не знаю, что еще использовать.Алгоритм выделения - когда длина совпадения не равна длине строки поиска

' cycle through search words and replace them in the text 
    For intWord = LBound(m_arrSearchWords) To UBound(m_arrSearchWords) 

     If m_arrSearchWords(intWord).Length > 0 Then 

      ' replace instances of the word with the word surrounded by bold codes 

      ' find starting position 
      intPos = strText.IndexOf(m_arrSearchWords(intWord), System.StringComparison.CurrentCultureIgnoreCase) 
      Do While intPos <> -1 

      strText = strText.Substring(0, (intPos - 1) - 0 + 1) & cstrHighlightCodeOn & strText.Substring(intPos, m_arrSearchWords(intWord).Length) & cstrHighlightCodeOff & strText.Substring(intPos + m_arrSearchWords(intWord).Length) 
      intPos = strText.IndexOf(m_arrSearchWords(intWord), intPos + m_arrSearchWords(intWord).Length + cstrHighlightCodeOn.Length + cstrHighlightCodeOff.Length, System.StringComparison.CurrentCultureIgnoreCase) 

      Loop 

     End If 

    Next intWord 

Метод подстроки не работает, поскольку длина находится за пределами строки. Я помещаю исправление для строк, которые заканчиваются поисковым термином (не показано выше). Но более длинные строки будут подсвечены неправильно, и мне нужно их исправить.

+0

Я также попытался Regex.Match с RegexOptions.CultureInvariant + RegexOptions.IgnoreCase но это, кажется, не совпадают на данном примере. –

ответ

-1

Если я правильно понимаю, вы ищете функцию, которая возвращает «Совпадение-строку» - другими словами, когда вы ищете s1 внутри s2, то вы хотите, чтобы точно знать, что было подобрано часть s2 (индекс первого и последнего совпадающих символов). Это позволяет выделить совпадение и не изменять строку (верхний/нижний регистр, лигатура и т. Д.).

У меня нет VB.net, и, к сожалению, у VBA нет одинаковых функций поиска, таких как VB.net - поэтому, пожалуйста, поймите, что следующий код правильно идентифицирует начало и конец матча, но это только проверены с совпадением верхнего/нижнего регистра. Надеюсь, это поможет вам решить проблему.

Option Compare Text 
Option Explicit 

Function startEndIndex(bigString, smallString) 
' function that returns start, end index 
' of the match 
' it keeps shortening the bigString until no match is found 
' this is how it takes care of mismatches in number of characters 
' because of a match between "similar" strings 
Dim i1, i2 
Dim shorterString 

i2 = 0 

' first see if there is a match at all: 
i1 = InStr(1, bigString, smallString, vbTextCompare) 

If i1 > 0 Then 
    ' largest value that i2 can have is end of string: 
    i2 = Len(bigString) 

    ' can make it shorter - but no shorter than twice the length of the search string 
    If i2 > i1 + 2 * Len(smallString) Then i2 = i1 + 2 * Len(smallString) 
    shorterString = Mid(bigString, i1, i2 - i1) 

    ' keep making the string shorter until there is no match: 
    While InStr(1, shorterString, smallString, vbTextCompare) > 0 
    i2 = i2 - 1 
    shorterString = Mid(bigString, i1, i2 - i1) 
    Wend 

End If 

' return the values as an array: 
startEndIndex = Array(i1, endOfString) 

End Function 


Sub test() 
' a simple test routine to see that things work: 
Dim a 
Dim longString: longString = "This is a very long TaesT of a complicated string" 
a = startEndIndex(longString, "very long taest") 
If a(0) = 0 And a(1) = 0 Then 
MsgBox "no match found" 
Else 
Dim highlightString As String 
highlightString = Left(longString, a(0) - 1) & "*" & Mid(longString, a(0), a(1) - a(0) + 1) & _ 
    "*" & Mid(longString, a(1) + 1) 
    MsgBox "start at " & a(0) & " and end at " & a(1) & vbCrLf & _ 
    "string matched is '" & Mid(longString, a(0), a(1) - a(0) + 1) & "'" & vbCrLf & _ 
    "with highlighting: " & highlightString 
End If 
End Sub 
+0

У этого есть проблема дублирования строки поиска. Я просто хочу поставить коды выделения до и после этого матча. Из-за нечувствительного к регистру и нечувствительного к культуре поиска строка поиска может быть не такой, как совпадение, которое оно находит. См. Пример выше для комбинированного символа ae. Но более простая разница в верхнем и нижнем регистре отбросит ваше предлагаемое решение. –

+0

@WillRickards - действительная критика. Посмотрите, показывает ли новый код лучшее понимание вашей проблемы. Я написал это в VBA - так что не совсем то решение, которое вы хотите, но это я мог проверить. Возьмите бит, который найдет правильные индексы согласованной строки и адаптирует его к вашим потребностям. Думаю, это сработает для вас. – Floris

0

Хотя было бы хорошо, если IndexOf вернет длину матча, оказывается, вы можете просто сделать сравнение самостоятельно, чтобы понять это. Я просто делаю вторичное сравнение с длиной, чтобы найти наибольшее совпадение. Я начинаю с длины искомого слова, которое должно быть самым большим. И затем подойдите назад, чтобы найти длину. Как только я нашел длину, я использую это. Если я не найду его, я проделаю свой путь в длину. Это работает, если строка, которую я ищу, больше или меньше. В нормальном случае это означает, по крайней мере, одно дополнительное сравнение, а в худшем случае - дополнительное число, основанное на длине слова поиска. Возможно, если бы у меня была реализация для IndexOf, я мог бы ее улучшить. Но, по крайней мере, это работает.

' cycle through search words and replace them in the text 
    For intWord = LBound(m_arrSearchWords) To UBound(m_arrSearchWords) 

     If m_arrSearchWords(intWord).Length > 0 Then 

      ' find starting position 
      intPos = strText.IndexOf(m_arrSearchWords(intWord), System.StringComparison.CurrentCultureIgnoreCase) 
      Do While intPos <> -1 

      intOrigLength = m_arrSearchWords(intWord).Length 

      ' if there isn't enough of the text left to add the search word length to 
      If strText.Length < ((intPos + intOrigLength - 1) - 0 + 1) Then 

       ' use shorter length 
       intOrigLength = ((strText.Length - 1) - intPos + 1) 

      End If 

      ' find largest match 
      For intLength = intOrigLength To 1 Step -1 

       If m_arrSearchWords(intWord).Equals(strText.Substring(intPos, intLength), StringComparison.CurrentCultureIgnoreCase) Then 

        ' if match found, highlight it 
        strText = strText.Substring(0, (intPos - 1) - 0 + 1) & cstrHighlightCodeOn & strText.Substring(intPos, intLength) & cstrHighlightCodeOff & strText.Substring(intPos + intLength) 

        ' find next 
        intPos = strText.IndexOf(m_arrSearchWords(intWord), intPos + intLength + cstrHighlightCodeOn.Length + cstrHighlightCodeOff.Length, System.StringComparison.CurrentCultureIgnoreCase) 

        ' exit search for largest match 
        Exit For 

       End If 

      Next 

      ' if we didn't find it by searching smaller - search larger 
      If intLength = 0 Then 

       For intLength = intOrigLength + 1 To ((strText.Length - 1) - intPos + 1) 

        If m_arrSearchWords(intWord).Equals(strText.Substring(intPos, intLength), StringComparison.CurrentCultureIgnoreCase) Then 

         ' if match found, highlight it 
         strText = strText.Substring(0, (intPos - 1) - 0 + 1) & cstrHighlightCodeOn & strText.Substring(intPos, intLength) & cstrHighlightCodeOff & strText.Substring(intPos + intLength) 

         ' find next 
         intPos = strText.IndexOf(m_arrSearchWords(intWord), intPos + intLength + cstrHighlightCodeOn.Length + cstrHighlightCodeOff.Length, System.StringComparison.CurrentCultureIgnoreCase) 

         ' exit search for largest match 
         Exit For 

        End If 

       Next 

      End If 

      Loop 

     End If 

    Next intWord 
Смежные вопросы