Page 1 of 2 12 LastLast
Results 1 to 40 of 41

Thread: QuoteSplit challenge

  1. #1

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    QuoteSplit challenge

    Make a Split function that skips quotes that contain the delimiter. Any opening quote will prevent delimeter from splitting the string.

    Syntax:
    VB Code:
    1. Public Function QuoteSplit(ByRef Expression As String, Optional ByRef Delimiter As String = " ", _
    2.     Optional ByVal Limit As Long, Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String()
    3.  
    4. End Sub

    This is a friendly challenge! This means that you can come up with entirely new suggestions, improve code posted earlier on and give suggestions to other participating in to the challenge.

    Purpose is free: you can aim for shortness, you can aim for speed, you can aim for balancing code length and speed. Do what you like most


    Edit!
    You may drop Limit and Compare if you don't want to do them.

    Also fixed Delimiter code (default = " ").

    Edit #2
    And now fixed the Delimiter spelling in the code.
    Last edited by Merri; Jan 5th, 2007 at 05:45 PM.

  2. #2
    "Digital Revolution"
    Join Date
    Mar 2005
    Posts
    4,471

    Re: QuoteSplit challenge

    I'll give it a go when I get some free time today.

  3. #3
    Oi, fat-rag! bushmobile's Avatar
    Join Date
    Mar 2004
    Location
    on the poop deck
    Posts
    5,592

    Re: QuoteSplit challenge

    [pedant]
    can I suggest that Delimiter be spelt correctly?
    [/pedant]

    and I shall also have a go at knocking something up

  4. #4
    Oi, fat-rag! bushmobile's Avatar
    Join Date
    Mar 2004
    Location
    on the poop deck
    Posts
    5,592

    Re: QuoteSplit challenge

    here's my not-much-code-but-slow version (i didn't bother with Limit):
    VB Code:
    1. Public Function QuoteSplit(ByRef Expression As String, Optional ByRef Delimiter As String = " ", Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String()
    2.     Dim sParts() As String, N As Long
    3.     sParts = Split(Expression, """")
    4.     For N = 0 To UBound(sParts) Step 2
    5.         sParts(N) = Replace(sParts(N), Delimiter, Delimiter & vbNullChar, , , Compare)
    6.     Next N
    7.     QuoteSplit = Split(Join(sParts, """"), Delimiter & vbNullChar)
    8. End Function
    you should provide some sort of example string Merri - this is the one i used:

    sText = "1 2 3 4 ""5 5a"" 6 ""8 8a"" 7"

  5. #5
    "Digital Revolution"
    Join Date
    Mar 2005
    Posts
    4,471

    Re: QuoteSplit challenge

    I'm tired so this code probably has bugs but I tested it a little. You'll probably find some if you test it.

    I'll get back to it later after I get some sleep.

    I provided a Start argument so you can choose where to start splitting from and also (hopefully) have the limit part working.

    It's probably buggy as hell but here it is:

    VB Code:
    1. Option Explicit
    2.  
    3. 'Count the number of instances a string appears within another string.
    4. Private Function InStrCount(ByVal Start As Long, ByRef Expression As String, ByRef SearchFor As String, _
    5.     Optional ByRef CompareMethod As VbCompareMethod = vbBinaryCompare) As Long
    6.    
    7.     If Start = 0 Then Exit Function
    8.     If Start > Len(Expression) Then Exit Function
    9.    
    10.     Dim lonPos As Long, lonCount As Long
    11.    
    12.     lonPos = InStr(Start, Expression, SearchFor, CompareMethod)
    13.    
    14.     Do While lonPos > 0
    15.         lonCount = lonCount + 1
    16.        
    17.         lonPos = InStr(lonPos + 1, Expression, SearchFor, CompareMethod)
    18.     Loop
    19.    
    20.     InStrCount = lonCount
    21.    
    22. End Function
    23.  
    24. Public Function QuoteSplit(ByVal Start As Long, ByRef Expression As String, Optional ByRef Delimiter As String = " ", _
    25.     Optional ByVal Limit As Long = -1, Optional ByVal CompareMethod As VbCompareMethod = vbBinaryCompare) As String()
    26.    
    27.     Dim lonLenEXP As Long
    28.    
    29.     lonLenEXP = Len(Expression)
    30.    
    31.     'Quick input checks...
    32.     If lonLenEXP = 0 Then Exit Function     'Expression is empty.
    33.     If Start = 0 Then Exit Function         'Start position is 0.
    34.     If Start > lonLenEXP Then Exit Function 'Start position is greater than length of expression.
    35.    
    36.     Dim strRet() As String 'Return value.
    37.     Dim lonPos As Long 'Position of delimiter.
    38.     Dim lonPrevPos As Long 'Previous position of delimiter.
    39.     Dim lon3Pos As Long 'Previous position of previous delimiter.
    40.     Dim bytInQuote As Byte 'Currently in quotations?
    41.     Dim lonQuoteCount As Long 'Number of quotes found.
    42.     Dim lonCount As Long 'Number of delimiters found (used for Limit argument).
    43.     Dim strTemp As String 'Temp string.
    44.     Dim lonStart As Long 'Temp start position.
    45.     Dim lonEnd As Long 'Temp long position.
    46.     Dim lonLenDelim As Long 'Length of delimiter.
    47.     Dim lonBnd As Long 'UBound of return value.
    48.     Dim strTmpCheck As String
    49.    
    50.     lonLenDelim = Len(Delimiter)
    51.    
    52.     'Find first delimiter.
    53.     lonPos = InStr(Start, Expression, Delimiter, CompareMethod)
    54.    
    55.     'Quick check.
    56.     If lonPos = 0 Then GoTo NoDelimiter
    57.    
    58.     'Keep looping while we can still find the delimiter.
    59.     Do While lonPos > 0
    60.        
    61.         'this,is,"a,test",abc
    62.        
    63.         '  "this,is",a,test
    64.         If lonPrevPos = 0 Then 'This is the first delimiter.
    65.             'Check if we're within quotes.
    66.             strTemp = Mid$(Expression, 1, lonPos - 1)
    67.            
    68.             lonQuoteCount = InStrCount(1, strTemp, Chr$(34), vbBinaryCompare)
    69.            
    70.             If lonQuoteCount Mod 2 = 0 Then
    71.                 bytInQuote = 0
    72.             Else
    73.                 bytInQuote = 1
    74.             End If
    75.            
    76.             If bytInQuote = 0 Then
    77.                 'Not in quotes.
    78.                 ReDim strRet(0) As String
    79.                
    80.                 strRet(0) = strTemp
    81.                 lonPrevPos = lonPos
    82.                
    83.                 lonCount = lonCount + 1
    84.                
    85.                 'Check if we're done.
    86.                 If lonCount = Limit Then
    87.                     QuoteSplit = strRet()
    88.                    
    89.                     Erase strRet()
    90.                     Exit Function
    91.                 End If
    92.                
    93.             Else
    94.                 lonPos = lonPos + 1
    95.             End If
    96.            
    97.         Else 'This is NOT the first delimiter.
    98.        
    99.             'this,is,"a,test",abc
    100.        
    101.             '  "this,is",a,test
    102.            
    103.             'Get text from previous delimiter to this one.
    104.             lonStart = lonPrevPos + lonLenDelim
    105.             lonEnd = lonPos
    106.            
    107.            
    108.             strTemp = Mid$(Expression, lonStart, lonEnd - lonStart)
    109.            
    110.             'Check if we're inside quotes.
    111.             lonQuoteCount = InStrCount(1, strTemp, Chr$(34), vbBinaryCompare) + CLng(bytInQuote)
    112.            
    113.             If lonQuoteCount Mod 2 = 0 Then
    114.                 bytInQuote = 0
    115.             Else
    116.                 bytInQuote = 1
    117.             End If
    118.            
    119.             If bytInQuote = 0 Then
    120.                 'Not in quotes.
    121.                 lonBnd = UBound(strRet()) + 1
    122.                
    123.                 ReDim Preserve strRet(0 To lonBnd) As String
    124.                
    125.                 strRet(lonBnd) = strTemp
    126.                
    127.                 lonCount = lonCount + 1
    128.                 lonPrevPos = lonPos
    129.                
    130.                 'Check if we're done.
    131.                 If lonCount = Limit Then
    132.                     QuoteSplit = strRet()
    133.                    
    134.                     Erase strRet()
    135.                     Exit Function
    136.                 End If
    137.                
    138.             Else
    139.                 lonPrevPos = lonPrevPos + 1
    140.             End If
    141.        
    142.         End If
    143.        
    144.         lonPos = InStr(lonPos + lonLenDelim, Expression, Delimiter, CompareMethod)
    145.     Loop
    146.    
    147.     'Check for text at end of string.
    148.     If lonPrevPos < lonLenEXP Then
    149.         lonBnd = UBound(strRet()) + 1
    150.        
    151.         ReDim Preserve strRet(0 To lonBnd) As String
    152.        
    153.         strRet(lonBnd) = Mid$(Expression, lonPrevPos + lonLenDelim)
    154.     End If
    155.    
    156.     QuoteSplit = strRet()
    157.    
    158.     Erase strRet()
    159.    
    160.     Exit Function
    161.    
    162. NoDelimiter:
    163.     'Just return the text like the Split() function does.
    164.     ReDim strRet(0) As String
    165.    
    166.     strRet(0) = Expression
    167.     QuoteSplit = strRet()
    168.    
    169.     Erase strRet()
    170. End Function
    171.  
    172. 'Test the function.
    173. Private Sub Command1_Click()
    174.     Dim strBuffer() As String
    175.    
    176.     strBuffer() = QuoteSplit(1, Text1.Text, "**")
    177.    
    178.     Dim intLoop As Integer
    179.    
    180.     On Error Resume Next 'For UBound error.
    181.    
    182.     List1.Clear
    183.    
    184.     For intLoop = 0 To UBound(strBuffer())
    185.         List1.AddItem strBuffer(intLoop)
    186.     Next intLoop
    187.    
    188. End Sub
    Last edited by DigiRev; Mar 26th, 2007 at 02:55 AM.

  6. #6
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: QuoteSplit challenge

    Here's mine:

    Though I'm not the type to write fast code, so I can't say it's optimized for speed.... this is just how I would write this function if I would need it...
    VB Code:
    1. Option Explicit
    2.  
    3. Private Sub Form_Load()
    4.     Dim sText As String
    5.     sText = "1 2 3 4 ""5 5a"" 6 ""8 8a"" 7"
    6.    
    7.     Debug.Print Join(QuoteSplit(sText), vbNewLine)
    8.     Debug.Print
    9.     Debug.Print Join(QuoteSplit(sText, , 6), vbNewLine)
    10. End Sub
    11.  
    12. Public Function QuoteSplit(ByRef Expression As String, Optional ByRef Delimeter As String = " ", _
    13.     Optional ByVal Limit As Long, Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String()
    14.    
    15.     Dim K As Long, InString As Boolean, LNDel As Long
    16.     Dim RetStr() As String, Count As Long, ArrSize As Long
    17.     Dim PrevPos As Long, Index As Long
    18.    
    19.     If Limit < 0 Then Limit = 0
    20.    
    21.     ' Count how many splits are neccessary
    22.     LNDel = Len(Delimeter)
    23.     K = 1
    24.     Do Until K > Len(Expression)
    25.         If InString Then
    26.             If Mid$(Expression, K, 1) = """" Then InString = False
    27.         Else
    28.             If Mid$(Expression, K, 1) = """" Then
    29.                 InString = True
    30.             ElseIf StrComp(Mid$(Expression, K, LNDel), Delimeter, Compare) = 0 Then
    31.                 Count = Count + 1
    32.                 K = K + LNDel - 1
    33.             End If
    34.         End If
    35.        
    36.         K = K + 1
    37.     Loop
    38.    
    39.     ' Resize the array
    40.     If Limit < Count And Limit > 0 Then
    41.         ArrSize = Limit - 1
    42.     Else
    43.         ArrSize = Count
    44.     End If
    45.    
    46.     ReDim RetStr(ArrSize)
    47.    
    48.     ' Fill in the parts/array
    49.     PrevPos = 1
    50.     K = 1
    51.     Do Until K > Len(Expression)
    52.         If InString Then
    53.             If Mid$(Expression, K, 1) = """" Then InString = False
    54.         Else
    55.             If Mid$(Expression, K, 1) = """" Then
    56.                 InString = True
    57.             ElseIf StrComp(Mid$(Expression, K, LNDel), Delimeter, Compare) = 0 Then
    58.                 If Index = ArrSize And Limit > 0 Then GoTo ReturnResult
    59.                
    60.                 RetStr(Index) = Mid$(Expression, PrevPos, K - PrevPos)
    61.                 Index = Index + 1
    62.                
    63.                 PrevPos = K + LNDel
    64.                 K = K + LNDel - 1
    65.             End If
    66.         End If
    67.        
    68.         K = K + 1
    69.     Loop
    70.    
    71. ReturnResult:
    72.     RetStr(ArrSize) = Mid$(Expression, PrevPos)
    73.    
    74.     QuoteSplit = RetStr
    75. End Function

  7. #7
    "Digital Revolution"
    Join Date
    Mar 2005
    Posts
    4,471

    Re: QuoteSplit challenge

    Did you write one Merri?

  8. #8
    Junior Member
    Join Date
    Jan 2003
    Posts
    24

    Re: QuoteSplit challenge

    WHY THIS CODE ?

    Private Sub Command1_click()
    Dim sText As String
    Dim sDelimiter as string
    sText = text1.text ' ie What you typing in the TextBox1
    sDelimiter = Text2.Text ' may be TWO ASTERICKS ** IN TEXTBOX2

    Arr = Split(sText, sDelimiter , , vbBinaryCompare)
    For i = 0 To UBound(Arr)
    Debug.Print Arr(i)
    Next i


    End Sub

  9. #9
    "Digital Revolution"
    Join Date
    Mar 2005
    Posts
    4,471

    Re: QuoteSplit challenge

    Quote Originally Posted by pearlxp
    WHY THIS CODE ?

    Private Sub Command1_click()
    Dim sText As String
    Dim sDelimiter as string
    sText = text1.text ' ie What you typing in the TextBox1
    sDelimiter = Text2.Text ' may be TWO ASTERICKS ** IN TEXTBOX2

    Arr = Split(sText, sDelimiter , , vbBinaryCompare)
    For i = 0 To UBound(Arr)
    Debug.Print Arr(i)
    Next i


    End Sub
    The point of this is to split a string, except for parts that are in quotes.

    I also figured we were supposed to do it without using the Split() function...if not then I just made it a lot harder than it needs to be.

  10. #10
    Oi, fat-rag! bushmobile's Avatar
    Join Date
    Mar 2004
    Location
    on the poop deck
    Posts
    5,592

    Re: QuoteSplit challenge

    Quote Originally Posted by DigiRev
    I also figured we were supposed to do it without using the Split() function...if not then I just made it a lot harder than it needs to be.
    you can use the Split function if you want - that's what it's there for - however, you'll be able to get faster results by not using it

    are any timings comparisons going to be run on these, Merri?

  11. #11

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    Just woke up from 40000 seconds of sleep, but I'll do one. I guess I could go for the "absolute insane optimization" line, which I don't normally do because it isn't practical at all I first thought about doing the very simple and minimal one, but bushmobile did it already.

    Anyways, I'll setup the timings first once I'm fully awake and have eat something.

    Also fixed the Delimiter/Delimeter typo in the first post.

  12. #12
    Oi, fat-rag! bushmobile's Avatar
    Join Date
    Mar 2004
    Location
    on the poop deck
    Posts
    5,592

    Re: QuoteSplit challenge

    Quote Originally Posted by Merri
    I guess I could go for the "absolute insane optimization" line, which I don't normally do because it isn't practical at all
    what would be the point of the challenge if you're not going to open a can of whoop-ass on us?

  13. #13

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    I try to do a maximum number of lines I can do for this simple task so you can laugh at how long it is It'll also take a few full work days to get it nice and good, a complete waste of time. The problem is that I'm unemployed at the moment as I'm waiting for getting an apartment in southern Finland to begin with a new job, so I have too much spare time...


    We could do an efficiency rating, ie. number of characters of required code vs. final speed. For character counting all comments should be ignored as well as indenting spaces and line changes. If someone wants to code it, you're welcome to do it.

  14. #14

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    The current results are rather equal in compiled code, surprisingly the shortest code by bushmobile is also the fastest. Under IDE bushmobile's code wipes the floor. Attached is the test project I made.

    DigiRev: you have an error in your function, you'll see the results when you download the speed comparison project attached below.


    The test string I used:
    VB Code:
    1. TESTSTRING = " """ & Space$(20) & """ """ & Space$(20) & """ "


    Edit!
    Attachment removed, see newer post for the benchmarker.
    Last edited by Merri; Jan 5th, 2007 at 10:57 PM.

  15. #15
    "Digital Revolution"
    Join Date
    Mar 2005
    Posts
    4,471

    Re: QuoteSplit challenge

    Quote Originally Posted by Merri
    DigiRev: you have an error in your function, you'll see the results when you download the speed comparison project attached below.


    The test string I used:
    VB Code:
    1. TESTSTRING = " """ & Space$(20) & """ """ & Space$(20) & """ "
    Yea I'm not surprised.

    I'll have to take a look at it tomorrow when I have time.

    Looking forward to seeing your version.

  16. #16

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    Warning! More related dangerous coding ideas coming!

    I guess we should talk about how the function should work in error situatations. I'd recommend working like the Split function: just return a string array with one element containing the expression string.

    However, there are troublesome cases when the delimiter contains quotes. My personal opinion is that if quotes are included in the delimiter, then delimiter is more important than quotes. So if a delimiter begins before a quote, then delimiter is more important and the quotes are ignored.

    Sample:
    • String: A "B" C (" A ""B"" C" on code)
    • QuoteSplit by " (" """ in code)
    • Result: QuoteSplit(0) = " A", QuoteSplit(1) = "B"" C"


    Does this sound ok behavior? I guess we should look for more troublesome cases so we can make an extensive validation so someone who needs this kind of function can see if it does work for what he needs; although I believe these functions do work for the most common need: split by space, ignore spaces quotes. Should we instead of allowing any delimiter only go for space delimiter?

    Then, should we add StripQuotes as an optional functionality? Meaning that quotes are removed from the final strings. I guess that is what is often wanted.

    And then: QuoteJoin! Do the opposite, add quotes for strings that contain the delimiter in the passed string array.

  17. #17

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    Ok, I now did my own function, however it is not aiming for superior speed. Instead it is more of the common "this is how I'd have done it if someone requested it". I wanted to get something ready sooner than later. Will see if I feel like starting to code the extreme speed version today or not.

    Attached is an upgraded project. Difference to what was before is that I put a generic code that swiches the testable function, one code to run all tests for all compatible functions. The downside is that all the testable functions must have identical syntax, so I could only make it work for bushmobile's and my own function for now. This means there is no support for Limit. These functions get additional validation test when ran.

    vb Code:
    1. Public Function Merri_QuoteSplit1(ByRef Expression As String, Optional ByRef Delimiter As String = " ", Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String()
    2.     Const QUOTE As String = """"
    3.     Static lngEnd() As Long, lngEndUB As Long
    4.     Dim strOut() As String
    5.     Dim lngPosQ As Long, lngPosQE As Long, lngPos As Long, lngCount As Long
    6.     Dim blnInQuote As Boolean, lngLen As Long
    7.     ' remember delimiter length
    8.     lngLen = Len(Delimiter)
    9.     ' error detection
    10.     If (lngLen = 0) Or (LenB(Expression) < LenB(Delimiter)) Then
    11.         ReDim strOut(0)
    12.         strOut(0) = Expression
    13.         Merri_QuoteSplit1 = strOut
    14.         Exit Function
    15.     End If
    16.     ' see if any quotes
    17.     lngPosQ = InStr(Expression, QUOTE)
    18.     ' no quotes? use Split!
    19.     If lngPosQ < 1 Then
    20.         Merri_QuoteSplit1 = Split(Expression, Delimiter, , Compare)
    21.         Exit Function
    22.     Else
    23.         ' ending quote
    24.         lngPosQE = InStr(lngPosQ + 1, Expression, QUOTE)
    25.     End If
    26.     ' see if any delimeters
    27.     lngPos = InStr(1, Expression, Delimiter, Compare)
    28.     If lngPosQE > 0 And lngPos > lngPosQ Then
    29.         lngPos = InStr(lngPosQE + 1, Expression, Delimiter, Compare)
    30.     End If
    31.     ' no delimeter or all quoted? get out!
    32.     If lngPos < 1 Or (lngPosQE <= 0 And lngPosQ < lngPos) Then
    33.         ReDim strOut(0)
    34.         strOut(0) = Expression
    35.         Merri_QuoteSplit1 = strOut
    36.         Exit Function
    37.     End If
    38.     ' reserve space if first time run
    39.     If lngEndUB = 0 Then lngEndUB = 40: ReDim lngEnd(lngEndUB)
    40.     ' then start off collecting indexes
    41.     Do Until lngPos < 1
    42.         ' need more space?
    43.         If lngEndUB < lngCount Then
    44.             lngEndUB = lngEndUB * 2
    45.             ReDim Preserve lngEnd(lngEndUB)
    46.         End If
    47.         ' check if found within a quote
    48.         blnInQuote = (lngPosQ < lngPos)
    49.         If blnInQuote And (lngPos < lngPosQE) Then
    50.             ' find next quote
    51.             lngPosQ = InStr(lngPosQE + 1, Expression, QUOTE)
    52.             ' found a next quote?
    53.             If lngPosQ > 0 Then
    54.                 lngPosQE = InStr(lngPosQ + 1, Expression, QUOTE)
    55.                 If lngPosQE <= 0 Then
    56.                     ' all remaining are belong to us
    57.                     Exit Do
    58.                 Else
    59.                     lngPos = InStr(lngPosQE + 1, Expression, Delimiter, Compare)
    60.                 End If
    61.             Else
    62.                 ' nope, there are no more quotes to worry about
    63.                 lngPos = InStr(lngPosQE + 1, Expression, Delimiter, Compare)
    64.                 lngPosQE = lngPosQ
    65.                 Exit Do
    66.             End If
    67.         Else
    68.             ' remember
    69.             lngEnd(lngCount) = lngPos + lngLen - 1
    70.             ' jump to next
    71.             lngCount = lngCount + 1
    72.             ' find next quote
    73.             lngPosQ = InStr(lngPos + lngLen, Expression, QUOTE)
    74.             ' look for next ending quote
    75.             If lngPosQ > 0 Then
    76.                 lngPosQE = InStr(lngPosQ + 1, Expression, QUOTE)
    77.                 If lngPosQE > 0 Then
    78.                     ' find next delimiter
    79.                     lngPos = InStr(lngPosQE + 1, Expression, Delimiter, Compare)
    80.                 Else
    81.                     ' all remaining are belong to us
    82.                     Exit Do
    83.                 End If
    84.             Else
    85.                 ' find next delimiter
    86.                 lngPos = InStr(lngPos + lngLen, Expression, Delimiter, Compare)
    87.                 ' huh, no quote found? we go out!
    88.                 Exit Do
    89.             End If
    90.         End If
    91.     Loop
    92.     ' see if we do unquoted work
    93.     If (lngPosQ < 1) And (lngPos > 0) Then
    94.         ' no quotes remaining, so we can work like this
    95.         Do Until lngPos < 1
    96.             ' need more space?
    97.             If lngEndUB < lngCount Then
    98.                 lngEndUB = lngEndUB * 2
    99.                 ReDim Preserve lngEnd(lngEndUB)
    100.             End If
    101.             ' remember
    102.             lngEnd(lngCount) = lngPos + lngLen - 1
    103.             ' jump to next
    104.             lngCount = lngCount + 1
    105.             ' find next
    106.             lngPos = InStr(lngPos + lngLen, Expression, Delimiter, Compare)
    107.         Loop
    108.     End If
    109.     ' need more space?
    110.     If lngEndUB < lngCount Then
    111.         lngEndUB = lngEndUB * 2
    112.         ReDim Preserve lngEnd(lngEndUB)
    113.     End If
    114.     ' add end of string
    115.     lngEnd(lngCount) = Len(Expression) + lngLen
    116.     ' reserve space for strings
    117.     ReDim Preserve strOut(lngCount)
    118.     ' get first item
    119.     strOut(0) = Left$(Expression, lngEnd(0) - lngLen)
    120.     ' get remaining items
    121.     For lngPos = 1 To lngCount
    122.         ' clip the one we need
    123.         strOut(lngPos) = Mid$(Expression, lngEnd(lngPos - 1) + 1, lngEnd(lngPos) - lngEnd(lngPos - 1) - lngLen)
    124.     Next lngPos
    125.     ' oh my god, we are done!
    126.     Merri_QuoteSplit1 = strOut
    127. End Function
    As you can see, bushmobile's code remains the best solution to give as a help despite this being the fastest
    Attached Files Attached Files
    Last edited by Merri; Mar 10th, 2007 at 01:06 AM.

  18. #18
    Hyperactive Member Maven's Avatar
    Join Date
    Feb 2003
    Location
    Greeneville, TN
    Posts
    322

    Re: QuoteSplit challenge

    Quote Originally Posted by Merri
    Make a Split function that skips quotes that contain the delimiter. Any opening quote will prevent delimeter from splitting the string.

    Syntax:
    VB Code:
    1. Public Function QuoteSplit(ByRef Expression As String, Optional ByRef Delimiter As String = " ", _
    2.     Optional ByVal Limit As Long, Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String()
    3.  
    4. End Sub

    This is a friendly challenge! This means that you can come up with entirely new suggestions, improve code posted earlier on and give suggestions to other participating in to the challenge.

    Purpose is free: you can aim for shortness, you can aim for speed, you can aim for balancing code length and speed. Do what you like most


    Edit!
    You may drop Limit and Compare if you don't want to do them.

    Also fixed Delimiter code (default = " ").

    Edit #2
    And now fixed the Delimiter spelling in the code.

    The extreme version would need to be done in C++ with asm =P

    If VB had bitwise operators, you could make a very fast one. This is very similar to what I'm doing in C, which is making a function that parses CGI input from a submit form or apache api. name=value&name=value2

    Here is a little slip of that code. It's actually pretty cool in that this algorithm can test 4 bytes at a time and only have 1 branch for each value I'm testing for. The example in this code is the amp & sign.

    // A very simple Key=Value parser =P
    int equal = 0x3d3d3d3d; // Mask for =
    int amp = 0x26262626; // Mask for &
    int teststr = 0;
    int maskstr = 0;
    unsigned int mask = 0;
    int y, m, n;
    int result = 4;

    char * key = str;
    char * value = 0;
    char * buf = 0;

    Code:
    This is an example of what asm can do that C++ cannot do:
    assign a int = char[3]. Note: always make sure you do this on a 4 byte boundry.
    
    
    magic:  	buf = &str[i];
    		__asm push eax
    		__asm push edx
    		__asm mov eax, dword ptr buf
    		__asm mov edx, [eax]    ; Get 4 charecters out of char *buf
    		__asm mov teststr, edx  ;Assign to int teststr.
    		__asm pop edx
    		__asm pop eax

    Code:
    		maskstr = teststr ^ amp;
    		mask = (maskstr & 0x7f7f7f7f) + 0x7f7f7f7f;
    		mask = ~(mask | maskstr | 0x7f7f7f7f);
    		
    		y = -(mask >> 16);    
    		m = (y >> 16) & 16;
    		n = 16 - m;      
    		mask = mask >> m;     
                          
    		y = mask - 0x100;     
    		m = (y >> 16) & 8; 
    		n = n + m; 
    		mask = mask << m; 
     
    		y = mask - 0x1000;    
    		m = (y >> 16) & 4;  
    		n = n + m; 
    		mask = mask << m; 
     
    		y = mask - 0x4000;     
    		m = (y >> 16) & 2;   
    		n = n + m; 
    		mask = mask << m; 
     
    		y = mask >> 14;        
    		m = y & ~(y >> 1);   
    		
    		result = (n + 2 - m) >> 3;
    
    
    		if(result != 4)
    		{
                            // str[location of amp] = 0
    			str[(i + 3) - result] = 0;
    			m_data[key] = value;  // STL MAP
    
    			key = &str[((i+3) - result)+1];		
                  }
    You could do a variation of this code in c++ and call it from vb I guess. Maybe do 2 charecters at a time from vb.net
    Last edited by Maven; Jan 6th, 2007 at 07:21 AM.
    Education is an admirable thing, but it is well to remember from time to time that nothing that is worth knowing can be taught. - Oscar Wilde

  19. #19
    Hyperactive Member Maven's Avatar
    Join Date
    Feb 2003
    Location
    Greeneville, TN
    Posts
    322

    Re: QuoteSplit challenge

    Yea with an algorithm that worked like this from visual basic.net, about 2 bytes at a time is all you could do. but that is still 1/2 the work =P

    just make sure your not testing for a NULL charecter, it'll work for everything but that. If it's null then you can't xor it with a mask. which is the first line.

    Basically what this algorithm does is read 4 bytes a time and load it into a integer. This integer is masked with a 4 byte mask of the character I'm testing for and then xored. That way if the value I'm testing for is located in the string, it'll be turned to a 00 NULL.

    Thats what this line does:
    int amp = 0x26262626; // Mask for &
    maskstr = teststr ^ amp;

    The next two lines just test to see if any of the 4 bytes have a null charecter.

    mask = (maskstr & 0x7f7f7f7f) + 0x7f7f7f7f;
    mask = ~(mask | maskstr | 0x7f7f7f7f);

    The rest of the lines just find out exactly where that null byte is in the word. The only reason u do this, is to avoid all branching (any kind of compares). At the end of the day, I ended up with just 1 branch per character I'm testing for in every 4 byte read, in the case of a CGI, that would be 2... the amp and the equal. Which means my algorithm is doing 1/4 the amount of branching that a obvious algorithm would do: aka a if string[i]== '=' then.

    I must point out to all those ASM bashes out there. When it comes to bit twiddling code, ASM is the clear winner! I couldn't get around using asm for this algorithm. To do so would have required me to load up the int 1 charecter at a time and shift 4 bytes each time, damn that.

    I'll probably end up rewriting the entire algorithm in ASM just because C compliers are very mysterious when it comes to inserting inline asm. At the end of the day, if its important enough for asm to be inserted, it's important enough to do in asm.

    Who says that? I say that! The useless programmer who spreads disinformation and demoralization wherever he goes.

    peace
    Education is an admirable thing, but it is well to remember from time to time that nothing that is worth knowing can be taught. - Oscar Wilde

  20. #20

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    Nobody is up to challenge bushmobile's short code with something relatively short, yet a bit faster? Or can someone figure out even a shorter code?

  21. #21
    Addicted Member
    Join Date
    Aug 2005
    Location
    York
    Posts
    197

    Re: QuoteSplit challenge

    Ummmm I think I did something similar before, under the name of ParseCSV (Not released tho), hangon - Ill dig out my code.
    EDIT: Yes I did, Ill need to make the interface compatible - because ','s are hardcoded in.
    Last edited by Raedwulf; Jan 7th, 2007 at 02:30 AM.

  22. #22

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    Do you want to have another kind of challenge already? Atleast it seems nobody is interested in finding other solutions to the current one (besides Raedwulf).

  23. #23
    Addicted Member
    Join Date
    Aug 2005
    Location
    York
    Posts
    197

    Re: QuoteSplit challenge

    I'll have to pass on this for a while, busy with exams. Since it is an open/not-too-serious challenge, i guess there shouldn't be any time limit. I'll post my solution when I get my exams over with, cheers .

    Have fun!

  24. #24
    PowerPoster jcis's Avatar
    Join Date
    Jan 2003
    Location
    Argentina
    Posts
    4,430

    Re: QuoteSplit challenge

    Not shorter but this is my version.
    VB Code:
    1. Public Function QuoteSplit(ByRef Expression As String, Optional ByRef Delimiter As String = " ", _
    2.          Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String()
    3.     Dim lStr        As String, lAuxExp As String
    4.     Dim lPos        As Long, lLastPos As Long
    5.     Dim Process     As Boolean
    6.        
    7.     lPos = InStr(lPos + 1, Expression, """", Compare)
    8.  
    9.     If lPos = 0 Then
    10.         QuoteSplit = Split(Expression, Delimiter, , Compare)
    11.         Exit Function
    12.     Else
    13.         If (UBound(Split(Expression, """", , Compare)) + 1) Mod 2 = 0 Then
    14.             MsgBox "Quote not closed", vbOKOnly + vbExclamation, "QuoteSplit"
    15.             Exit Function
    16.         End If
    17.     End If
    18.  
    19.     lLastPos = 1
    20.     Process = True
    21.     lAuxExp = Expression
    22.     While lPos
    23.         If Process Then 'Like step 2 but using this boolean
    24.             lStr = Mid$(Expression, lLastPos, lPos - lLastPos)
    25.             Mid$(lAuxExp, lLastPos, lPos - lLastPos) = Replace(lStr, Delimiter, """") 'Replace single space with "
    26.         End If
    27.         lPos = lPos + 1
    28.         lLastPos = lPos
    29.         Process = Not Process
    30.         lPos = InStr(lPos, Expression, """", Compare)
    31.        
    32.         If lPos = 0 And Process Then
    33.             lPos = Len(Expression) + 1
    34.             Process = True
    35.         End If
    36.     Wend
    37.     QuoteSplit = Split(lAuxExp, """", , Compare)
    38. End Function
    Edit: Made some changes
    Last edited by jcis; Jan 12th, 2007 at 06:58 PM.

  25. #25

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    Quote Originally Posted by jcis
    It might still need some changes.
    It does, because it doesn't pass any of the test strings in the validation and benchmark. Runs into an error. Too tired to think more than this.

  26. #26
    PowerPoster jcis's Avatar
    Join Date
    Jan 2003
    Location
    Argentina
    Posts
    4,430

    Re: QuoteSplit challenge

    Quote Originally Posted by Merri
    Do you want to have another kind of challenge already? Atleast it seems nobody is interested in finding other solutions to the current one (besides Raedwulf).
    I was thinking about an smart Replace, a Replace function that allows a Pattern in the Find parameter using a wildcard character, i think it could be useful.
    Same Syntax than Replace:
    VB Code:
    1. Public Function SmartReplace(pExpression As String, _
    2.                              pFind As String, _
    3.                              pReplace As String, _
    4.                              Optional pStart As Long = 1, _
    5.                              Optional pCount As Long = -1, _
    6.                              Optional pCompare As VbCompareMethod = vbBinaryCompare) As String
    The character * could be used as wildcard, some examples:

    pExpression = "abc abcd abcde AAA"
    pFind = "abc*"
    pReplace = "1"

    String Returned: "1 1 1 AAA"
    Blank spaces " " delimit replacing zones, even the wildcards can't go beyond them.

    Another example:
    pExpression = " abc cabc abzt"
    pFind = " ab*"
    pReplace = "P"

    String Returned: "P cabcP".

    Another..
    pExpression = "Hi, how are you?"
    pFind = "y*u"
    pReplace = "they"

    String Returned: "Hi, how are they?"

    One more with numbers:
    pExpression = "123 - 627 = 0"
    pFind = "*2*"
    pReplace = "5"

    String Returned: "5 - 5 = 0"

    This kind of smart Replace is native in Java but I never saw it in other programming languages, maybe Regex in .Net.
    I know this doesn't seem very easy to do, but i think it would be useful, what do you people think?
    Last edited by jcis; Jan 13th, 2007 at 06:08 AM.

  27. #27

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    I don't care as much about SmartReplace (and I don't see major trouble in it, unless one targets for speed), but how about MultiReplace? Many people seem to have problems with doing several replaces at once, so how about making it possible to pass string arrays as Find and Replace?

    The difficulty is that it should always look for the next match in the string and replace that, ie. just doing multiple replaces in a row does not work.


    So now we have SmartReplace and MultiReplace as a new challenge.

  28. #28
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: QuoteSplit challenge

    I like the SmartReplace idea.

    How about functions so simulate the commands in Unix/Linux (for strings) ?

    When I learned unix at school, I found the functions quite usefull.

    You could find data by pattern, modify, replace... it was so long ago that I don't even remember the functions names, I just remember that they were quite usefull for manipulating strings...

  29. #29

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    So, we'll code SmartReplace as it already interests two persons At the moment I don't have the time though, but I'll see what is the situatation tomorrow or later on in this week. Finally opened a development site, it took less time to get it somewhat running than I expected, but getting it to final polished shape will take some time... and creating all the content will surely take my time. I thought about collecting a function library and putting results of these available there if people are willing to contribute

  30. #30
    Oi, fat-rag! bushmobile's Avatar
    Join Date
    Mar 2004
    Location
    on the poop deck
    Posts
    5,592

    Re: QuoteSplit challenge

    I'd be willing to give that a shot - maybe the thread should be put in the Contests forum this time - might get a bit more notice *shrug*

    the SmartReplace might be a bit more of a challenge if it allowed other wildcards, ? and # for instance (and any other ones that people can think of)

    what say you?

  31. #31

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    Also, we might want to add escape character, like \, to allow searching for the wildcards characters. So \\ would represent single \ character, \* would represent * character (and not a wildcard for any characters).

    But I guess we could go for "optional", so a basic function could only support the wildcard * and function creator could tell which wildcards his function supports when he contributes his own solution. Of course, the more it supports, the better

    * = none, or any number of characters
    ? = any one character
    # = any one number
    \ = escape character


    Edit!
    I now wrote a page about the last challenge to Devve: QuoteSplit Challenge. I chose bushmobile's and CVMichael's code there besides mine as these were the ones that worked as expected
    Last edited by Merri; Jan 15th, 2007 at 04:47 AM.

  32. #32
    Addicted Member
    Join Date
    Aug 2005
    Location
    York
    Posts
    197

    Re: QuoteSplit challenge

    Why not Regular Expression, search and replace?
    Would be along the lines of your SmartReplace, but more practical?

  33. #33

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    As far as I know, a fast version of a regular expression is easily readily available via some object. Never used it, but seen a few threads about it. So that takes value out of doing it.

  34. #34
    Addicted Member
    Join Date
    Aug 2005
    Location
    York
    Posts
    197

    Re: QuoteSplit challenge

    AFAIK, the regexp object is quite slow. I mean a trimmed down version - less bells and whistles, more speed.

  35. #35

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    If so, define what you mean. From what I know, regexp is always defined to function the same way, ie. regexps in Linux work the same as regexp in Windows. Maybe I should bother reading Wikipedia, but I guess I feel a bit lazy now.

  36. #36
    New Member TOQ4's Avatar
    Join Date
    Feb 2007
    Location
    Walldorf, Germany
    Posts
    7

    Re: QuoteSplit challenge

    Lets see how this code does!

    I didn't get your "Merri" code to split correct don't know why; bushmobile's code is fantastic in a lot of aspects but:

    I have chosen slightly different approach, lets make a piece of code that is serializable; in this way we can parse very large data; we don't use any extra memory.... We can tell how far we are - maybe even skip data...

    my code is a bit shorter than other code; would normally wrap it in a class - for now i have some static variables; not so good but it shows how I believe is the best way to parse data.

    I will not claim that I have verified it; but it works on my test-strings; performs OK in the IDE and really good compiled. TQ1 is returning an array, TQ2 is streaming the data....

    Use:

    Code:
      Dim i as long, a as string
      Do
        a = QuoteSplitStream(i,......)
        ' i tells you how far we are in the string
      loop until i=0
    Code:

    Code:
    Public Function TOQ_QuoteSplitStream(ByRef i As Long, ByRef Expression As String, Optional ByRef Delimiter As String = " ", Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String
    
      Dim j As Long
      Static k As Long, lE As Long, lD As Long
      If i = 0 Then k = 0: lE = Len(Expression): lD = Len(Delimiter)
      If k = 0 Then k = InStr(i + 1, Expression, """"): If k = 0 Then k = lE + 1
      If i + 1 = k Then
        j = InStr(i + 2, Expression, """")
        If j = 0 Then Err.Raise "Unclosed quote"
        TOQ_QuoteSplitStream = Mid$(Expression, i + 1, j - i) ' Including quotes, don't know it it makes sense to return the quotes
        j = j + lD ' Because we assume that a quote is followed by a delimiter
        k = 0
      Else
        j = InStr(i + 1, Expression, Delimiter, Compare)
        If j = i + 1 Then
          j = i + lD
          TOQ_QuoteSplitStream = ""
        Else
          If j = 0 Then j = lE + 1
          If k < j Then
            j = k + lD
            TOQ_QuoteSplitStream = Mid$(Expression, i + 1, j - i)
            k = 0
          Else
            TOQ_QuoteSplitStream = Mid$(Expression, i + 1, j - i - 1)
            j = j + lD - 1
          End If
        End If
      End If
      i = j
      If i >= lE Then i = 0
      
    End Function
    
    Public Function TOQ_QuoteSplit(ByRef Expression As String, Optional ByRef Delimiter As String = " ", Optional ByVal Compare As VbCompareMethod = vbBinaryCompare) As String()
      
      Const cGuess = 16
      
      Dim i As Long, j As Long, s() As String
      ReDim Preserve s(cGuess - 1)
      Do
        If j Mod cGuess = cGuess - 1 Then
          ReDim Preserve s(j + cGuess)
        End If
        s(j) = TOQ_QuoteSplitStream(i, Expression, Delimiter, Compare)
        j = j + 1
      Loop Until i = 0
      ReDim Preserve s(j - 1)
      TOQ_QuoteSplit = s
      
    End Function
    Benchmark IDE:

    Expression:"1 2 3 4 "5 5a" 6 "8 8a" 7"
    Delimiter:" "
    Iterations:5000

    Bushmobile = 125ms 8:|1|2||3|4|"5 5a"|6|"8 8a"|7|
    Merri = 26ms 3:|1|2 3 4 "5 5a"|6 "8 8a"|7|
    TOQ1 = 63ms 8:|1|2||3|4|"5 5a"|6|"8 8a"|7|
    TOQ2 = 41ms

    Expression:"1 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 7"
    Delimiter:" "
    Iterations:1000
    Bushmobile = 92ms 35:|1|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|7|
    Merri = 47ms 11:|1|2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|7|
    TOQ1 = 47ms 35:|1|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|7|
    TOQ2 = 33ms

    Expression:"1 2 3 4 "5 5a" 6 "8 8a" 7"
    Delimiter:" "
    Iterations:5000
    Bushmobile = 116ms 7:|1|2|3|4|"5 5a"|6|"8 8a"|7|
    Merri = 27ms 3:|1|2 3 4 "5 5a"|6 "8 8a"|7|
    TOQ1 = 56ms 7:|1|2|3|4|"5 5a"|6|"8 8a"|7|
    TOQ2 = 37ms

    Benchmark Compiled:

    Expression:"1 2 3 4 "5 5a" 6 "8 8a" 7"
    Delimiter:" "
    Iterations:5000
    Bushmobile = 174ms 8:|1|2||3|4|"5 5a"|6|"8 8a"|7|
    Merri = 14ms 3:|1|2 3 4 "5 5a"|6 "8 8a"|7|
    TOQ1 = 33ms 8:|1|2||3|4|"5 5a"|6|"8 8a"|7|
    TOQ2 = 15ms

    Expression:"1 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 71 2 3 4 "5 5a" 6 "8 8a" 7"
    Delimiter:" "
    Iterations:1000
    Bushmobile = 88ms 35:|1|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|7|
    Merri = 9ms 11:|1|2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|71 2 3 4 "5 5a"|6 "8 8a"|7|
    TOQ1 = 25ms 35:|1|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|71|2|3|4|"5 5a"|6|"8 8a"|7|
    TOQ2 = 13ms

    Expression:"1 2 3 4 "5 5a" 6 "8 8a" 7"
    Delimiter:" "
    Iterations:5000
    Bushmobile = 119ms 7:|1|2|3|4|"5 5a"|6|"8 8a"|7|
    Merri = 14ms 3:|1|2 3 4 "5 5a"|6 "8 8a"|7|
    TOQ1 = 29ms 7:|1|2|3|4|"5 5a"|6|"8 8a"|7|
    TOQ2 = 14ms
    Last edited by TOQ4; Feb 13th, 2007 at 03:49 PM.

  37. #37

    Thread Starter
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: QuoteSplit challenge

    TOQ4: your code works incorrectly, however your test string also triggered a bug in my code, which I've now fixed in the post where I originally submitted it.

  38. #38
    Kitten CornedBee's Avatar
    Join Date
    Aug 2001
    Location
    In a microchip!
    Posts
    11,594

    Re: QuoteSplit challenge

    Did someone mention C++?

    This
    Code:
    template <typename C>
    void csv_split(
    	std::vector< std::basic_string<C> > &out,
    	std::basic_string<C> const &in,
    	std::basic_string<C> const &delimiter = ",",
    	std::size_t limit = -1,
    	std::basic_string<C> const &quoter = "\"'",
    	std::basic_string<C> const &escaper = "\\")
    {
    	typedef boost::escaped_list_separator<C> sepfunc_t;
    	typedef boost::tokenizer<sepfunc_t> tokenizer_t;
    	tokenizer_t tok(in, sepfunc_t(escaper, delimiter, quoter));
    	tokenizer_t from = tok.begin(), to = tok.end();
    	while(from != to && limit > 0) {
    		out.push_back(*from++);
    	}
    	while(from != to) {
    		out.back().append(*from++);
    	}
    }
    I've left out the casing parameter, as it doesn't make much sense: case-insensitive with respect to what? It could only be the separator, and how often do you use an alphabetic character as separator?

    And if you really need to, this version accepts multiple separators (and quoters and escapers), so if you really need to split on 'a', regardless of case, you can simply do this:
    Code:
    std::vector<std::string> result;
    csv_split(result, "ThisastringamustAbeAsplitaonAstuff", "Aa");
    All the buzzt
    CornedBee

    "Writing specifications is like writing a novel. Writing code is like writing poetry."
    - Anonymous, published by Raymond Chen

    Don't PM me with your problems, I scan most of the forums daily. If you do PM me, I will not answer your question.

  39. #39
    Member cleverconcepts's Avatar
    Join Date
    Mar 2007
    Location
    Australia
    Posts
    44

    Re: QuoteSplit challenge

    ok well i didn't test it at all, however, should be speedy:

    Code:
    Function ParseExceptQuotes(ByRef sText$, ByRef sParse$) As Variant
    
        Dim tba() As Byte, pba() As Byte, oba() As Byte, i&, j&, bq As Boolean, s$, u&, c&, uu&, opa
        tba = StrConv(sText, vbFromUnicode): pba = StrConv(sParse, vbFromUnicode)
        ReDim opa(1000) As String: c = -1
        u = UBound(tba): uu = UBound(pba)
        
        For i = 0 To u
            If tba(i) = 34 Then bq = Not bq
            If bq Then
                 s = s & Chr$(tba(i))
            Else
                If tba(i) = pba(0) Then
                    If uu > 1 Then
                        For j = 1 To uu
                            If tba(i + j) <> pba(j) Then Exit For
                        Next j
                    End If
                    If j = uu Then
                        ' found delimiter
                        c = c + 1
                        opa(c) = s
                        s = ""
                    End If
                    i = i + j
                Else
                    s = s & Chr$(tba(i))
                End If
            End If
            
            If i = u Then
                opa(c + 1) = s
                ReDim Preserve opa(c + 1) As String
                ParseExceptQuotes = opa
            End If
        Next i
    End Function
    usage:
    Code:
    Private Sub Command1_Click()
    Dim s$, a, i&
    s = "1 2 3 4 ""5 5a"" 6 ""8 8a"" 7"
    a = ParseExceptQuotes(s, " ")
    For i = 0 To UBound(a)
        Debug.Print a(i)
    Next i
    End Sub
    bleh

  40. #40
    Fanatic Member bgmacaw's Avatar
    Join Date
    Mar 2007
    Location
    Atlanta, GA USA
    Posts
    524

    Re: QuoteSplit challenge

    If you're in the "Don't bark if you have a dog to do it for you" school of thought, here's an example of this function using VS2005 VB.NET's built-in Text Parsing engine.

    vb Code:
    1. Public Function QuoteSplit(ByVal parseString As String, ByVal ParamArray Delimiters() As String) As String()
    2.         Dim Results() As String
    3.         Dim StringEncoding As New ASCIIEncoding()
    4.         Using MemStream As New MemoryStream(StringEncoding.GetBytes(parseString))
    5.             Using Parser As New FileIO.TextFieldParser(MemStream)
    6.                 Parser.Delimiters = Delimiters
    7.                 Parser.HasFieldsEnclosedInQuotes = True
    8.                 Results = Parser.ReadFields()
    9.             End Using
    10.         End Using
    11.         Return Results
    12. End Function

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width