Как я мог переписать это, чтобы удалить gotos без потери скорости или читабельности? - PullRequest
0 голосов
/ 14 июня 2009

Я написал это. Да, я знаю, что это VB6. Да, это производственный код, и да, я знаю, что он использует gotos. Я ленивый, злой зверь ...

Итак, покажи мне (и остальным), как это должно быть написано

Public Function SplitString(ByVal sText As Variant) As Variant
    Dim nHere As Long
    Dim cHere As String * 1
    Dim aRes As Variant
    Dim nRes As Long
    Dim bInquote As Boolean
    Dim sString As String
    ReDim aRes(0)
    nHere = 1
    nRes = 0
    Do
    If nHere > Len(sText) Then Exit Do
    cHere = Mid$(sText, nHere, 1)
    If cHere = Chr$(32) Then
        If bInquote Then
        sString = sString & cHere
        GoTo nextChar
        End If
        If sString <> vbNullString Then
        aRes(nRes) = sString
        sString = vbNullString
        nRes = nRes + 1
        ReDim Preserve aRes(nRes)
        End If
        GoTo nextChar
    ElseIf cHere = Chr$(34) Then
        bInquote = Not bInquote
        GoTo nextChar
    Else
        sString = sString & cHere
    End If
nextChar:
    nHere = nHere + 1
    Loop
    If sString <> vbNullString Then
    aRes(nRes) = sString
    End If
    SplitString = aRes
End Function

Кстати, он разбивает строку на массив. Элементы в строке могут быть заключены в кавычки.

Ответы [ 6 ]

6 голосов
/ 14 июня 2009

Все довольно просто:

Измените «If sString <> vbNullString Then» на «ElseIf sString <> vbNullString Then», удалите все «Goto» и удалите «nextChar:».

Public Function SplitString(ByVal sText As Variant) As Variant
    Dim nHere As Long
    Dim cHere As String * 1
    Dim aRes As Variant
    Dim nRes As Long
    Dim bInquote As Boolean
    Dim sString As String
    ReDim aRes(0)
    nHere = 1
    nRes = 0
    Do
        If nHere > Len(sText) Then Exit Do
        cHere = Mid$(sText, nHere, 1)
        If cHere = Chr$(32) Then
            If bInquote Then
                sString = sString & cHere
            ElseIf sString <> vbNullString Then
                aRes(nRes) = sString
                sString = vbNullString
                nRes = nRes + 1
                ReDim Preserve aRes(nRes)
            End If
        ElseIf cHere = Chr$(34) Then
            bInquote = Not bInquote
        Else
            sString = sString & cHere
        End If

        nHere = nHere + 1
    Loop
    If sString <> vbNullString Then
        aRes(nRes) = sString
    End If
    SplitString = aRes
End Function
2 голосов
/ 16 июня 2009

Вы должны взглянуть здесь, чтобы понять, как тонкие оптимизации влияют на такую ​​задачу:

http://www.xbeat.net/vbspeed/c_Split.htm

Вы увидите, что среди этих алгоритмов нет ни одного лучшего одного, а скорее довольно хороших, а затем и тех, которые действительно могут кричать обидчикам немного лучше, чем другие.

2 голосов
/ 14 июня 2009

Я согласен, что этот конкретный фрагмент логики должен быть четко и легко реализован с помощью операций Split () и Join (). В то время как всегда можно написать длинный код встроенного кода, который улучшает их скорость, есть две причины не делать этого:

  • Разница в производительности, вероятно, даже не достигнет коэффициента 1,5, и такая логика редко используется миллионы раз на очень больших строках.
  • Такая встроенная логика не только непрозрачна и сложна в обслуживании, но с первого раза трудно понять, когда пишется программа.

Пример:

Function SplitString(ByVal Text As String) As String()
    Dim Slices() As String
    Dim UnquotedSlice As Long

    Slices = Split(Text, """")
    For UnquotedSlice = 0 To UBound(Slices) Step 2
        Slices(UnquotedSlice) = Replace$(Slices(UnquotedSlice), " ", vbNullChar)
    Next
    SplitString = Split(Join$(Slices, ""), vbNullChar)
End Function

Кстати: спасибо всем, кто может исправить неправильную разметку кода, которую использует этот сайт в моем примере выше.

Редактировать: Неважно, я выдохнул. Маркированный список вызвал у парсера спазм.

1 голос
/ 14 июня 2009

Я слышал эмпирическое правило, которое гласит, что если ваш goto прыгает вперед, это, вероятно, хорошо. Это похоже на один из тех случаев. Если вы можете изменить логику предиката, то, кажется, легче.

0 голосов
/ 14 июня 2009

Я бы просто использовал функции Split и Функции соединения , которые являются родными для VB6. Я оставлю вам детали, но основной поток состоит в том, чтобы разделить пробелы и затем воссоединиться с объектами, которые между кавычками.

Я не писал VB6 в течение многих лет, и у меня нет установленного программного обеспечения (для отладки), поэтому я не хочу проверять функцию.

Удачи,
Frank

0 голосов
/ 14 июня 2009

Выглядит довольно прямо. Просто используйте структуру if / else. Если ваш код входит в блок if, он никогда не войдет в соответствующие блоки elseif или else. Во-первых, многие ваши операторы goto даже не нужны.

Public Function SplitString(ByVal sText As Variant) As Variant
    Dim nHere As Long
    Dim cHere As String * 1
    Dim aRes As Variant
    Dim nRes As Long
    Dim bInquote As Boolean
    Dim sString As String
    ReDim aRes(0)
    nHere = 1
    nRes = 0
    Do
        If nHere > Len(sText) Then Exit Do
        cHere = Mid$(sText, nHere, 1)
        If cHere = Chr$(32) Then
            If bInquote Then
                sString = sString & cHere
            ElseIf sString <> vbNullString Then
                aRes(nRes) = sString
                sString = vbNullString
                nRes = nRes + 1
                ReDim Preserve aRes(nRes)
            End If
        ElseIf cHere = Chr$(34) Then
            bInquote = Not bInquote
        Else
            sString = sString & cHere
        End If
        nHere = nHere + 1
    Loop
    If sString <> vbNullString Then
        aRes(nRes) = sString
    End If
    SplitString = aRes
End Function
...