【问题标题】:Excel VBA split CSV files a certain orderExcel VBA按一定顺序拆分CSV文件
【发布时间】:2015-05-14 12:51:01
【问题描述】:

此代码采用 CSV 文件,例如:

"Penn National Gaming, Inc.",16.28
"iShares 20 Year Treasury Bond E",118.88
"iShares MSCI Emerging Index Fun",42.40

第 1 步

第 0 行: ""Penn National Gaming, Inc.",16.28

第 1 行:“iShares 20 年期国债 E”,118.88

第 2 行:“iShares MSCI Emerging Index Fun”,42.40

第 2 步

它需要第0行并进入:

值 0: Penn National Gaming

价值 1: , Inc.

值 2: 16.28

我的问题是:我怎样才能做到:

值 0: Penn National Gaming Inc.

值 1: 16.28

在Value 0中本质上结合全名(可能包含多于1个逗号)并保持value 1不变,但同时,仍然管理以逗号分隔 CSV 传递的数据。我在考虑某种顺序(从 Line 1 中从行尾开始删除 1 个逗号,但我找不到办法。

谢谢!

Dim Resp As String: Resp = Http.ResponseText
Dim Lines As Variant: Lines = Split(Resp, vbLf)
Dim sLine As String
Dim Values As Variant

For i = 0 To UBound(Lines)
    sLine = Lines(i)
       If InStr(sLine, ",") > 0 Then
        Values = Split(sLine, ",")

【问题讨论】:

    标签: excel vba csv yahoo-api yahoo-finance


    【解决方案1】:

    这是一个有趣的问题。我想出了一个通用函数,它适用于 csv 行中任意数量的非引用和引用值,其中引用的值可能包含也可能不包含逗号。

    测试线: "Penn National Gaming, Inc.",16.28
    输出:

        Value[0] = Penn National Gaming, Inc.  
        Value[1] = 16.28  
    

    测试线: a,b,c,"some, commas, here",16.28,"some,commas,there",17.123
    输出:

        Value[0] = a  
        Value[1] = b  
        Value[2] = c  
        Value[3] = some, commas, here  
        Value[4] = 16.28  
        Value[5] = some,commas,there  
        Value[6] = 17.123 
    
    1. 我首先在该行中搜索了成对的引号“...”。

    2. 在每对引号中,我搜索了逗号,并将它们替换为我认为永远不会正常出现的字符,replacementCharacter = "¯",(如果需要,您可以选择不同的字符)。

    3. 替换引用的逗号后,我使用Split() 函数将行分隔为逗号。

    4. 然后我遍历生成的数组并将所有替换字符替换为逗号。

    我使用给出的具体示例和一个更一般的混合引号逗号值和值的示例测试了我的代码:

    代码:

    Function parseLine(sLine)
        Dim Value As Variant
        Dim i As Integer
    
        quote = """"
        delimiter = ","
        replacementCharacter = "¯"
    
        'get first pair of quotes
        currentQuoteIndex = InStr(1, sLine, quote) 'get first quote
        If (currentQuoteIndex = 0) Then
            nextQuoteIndex = 0
        Else
            nextQuoteIndex = InStr(currentQuoteIndex + 1, sLine, quote) 'get next quote
        End If
    
        'get pairs of quotes and replace commas with replacementCharacter
        Do While nextQuoteIndex <> 0 And currentQuoteIndex <> 0
    
            subString = Mid(sLine, currentQuoteIndex + 1, nextQuoteIndex - currentQuoteIndex - 1)
            subString = Replace(subString, comma, replacementCharacter)
            sLine = Left(sLine, currentQuoteIndex - 1) + subString + Right(Mid(sLine, nextQuoteIndex + 1), Len(sLine))
    
            'get next pair of quotes
            currentQuoteIndex = InStr(nextQuoteIndex + 1, sLine, quote) 'get first quote
            If (currentQuoteIndex = 0) Then
                nextQuoteIndex = 0
            Else
                nextQuoteIndex = InStr(currentQuoteIndex + 1, sLine, quote)  'get next quote
            End If
        Loop
    
        'split string by commas
        Values = Split(sLine, delimiter)
    
        'replace replacementCharacter with commas
        For i = 0 To UBound(Values)
            Values(i) = Replace(Values(i), replacementCharacter, delimiter)
        Next
        parseLine = Values
    End Function
    

    此函数适用于包含引号字符串的任意数量的逗号,列的顺序不限。

    【讨论】:

    • 感谢您的详细解答。我尝试集成它,但由于某种原因它不起作用。值 0,1 和 2 仍然相同,并且 1 和 2 未分组。您知道可能是什么原因吗?您能否就与我的完整代码的实际集成给我一些指导?谢谢!
    【解决方案2】:

    以下简单解决方案标识最后一个逗号的位置。该信息用于确定全名和价格在行内的位置。最终结果是一个包含 2 个值的数组。

    注意:全名中的附加逗号将被忽略,因为使用了非逗号“,”过程

    Dim Resp As String: Resp = Http.ResponseText
    Dim Lines As Variant: Lines = Split(Resp, vbLf)
    Dim sLine As String
    Dim Values(1) As Variant
    
    For i = 0 To UBound(Lines)
        sLine = Lines(i)   
    
        'Reduced complexity by avoiding the need to split on commas ","
        Values(0) = left(sLine,instrrev(sLine,",")-1)  'Full Name
        Values(1) = mid(sLine,instrrev(sLine,",")+1)   'Price value
    Next
    

    使用函数

    Dim Resp As String: Resp = Http.ResponseText
    Dim Lines As Variant: Lines = Split(Resp, vbLf)
    Dim sLine As String
    Dim Values(1) As Variant
    
    Function extractData(sLine as String)
      Dim tmpArray(1) As Variant
    
      'Reduced complexity by avoiding the need to split on commas ","
      tmpArray(0) = left(sLine,instrrev(sLine,",")-1)  'Full Name
      tmpArray(1) = mid(sLine,instrrev(sLine,",")+1)   'Price value
    
      extractData = tmpArray
    
    End Function
    
    For i = 0 To UBound(Lines)
        sLine = Lines(i)   
        Values = extractData(sLine)
    Next
    

    输出:

    值 0:Penn National Gaming, Inc.

    值 1:16.28

    【讨论】:

    • 嗨@Stelian,如果这个或任何答案已经解决了您的问题,请点击复选标记考虑accepting it。这向更广泛的社区表明您已经找到了解决方案,并为回答者和您自己提供了一些声誉。没有义务这样做。
    • 这不提供通用解决方案。请注意,OP 说字符串可能采用以下格式:“”Penn National Gaming, Inc.”,16.28 “iShares 20 Year Treasury Bond E”,118.88 “iShares MSCI Emerging Index Fun”,42.40。您的解决方案应该能够解析该行并将其转换为一个数组。
    • 这是一个基于OP提供的代码和示例的点解决方案。你是对的,我的解决方案将处理 CSV 文件的每一行。通过仔细检查 OP 帖子,人们会注意到示例“Penn National Gaming, Inc.”、16.28“iShares 20 年期国债 E”、118.88“iShares MSCI Emerging Index Fun”、42.40 分布在 vbLf 的多个行中。由于格式化,这仅在编辑模式下可见。我会将代码放置在适当的容器(即代码块)中,以正确说明 OP 的意图。如果您有任何其他疑虑,请告诉我。 @Brino
    • 好收获。有时 SO 在其帖子中包含/排除空白字符。
    • 在整合这段代码时,我在Values(0)的第一行得到Type Mismatch,你知道为什么吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 1970-01-01
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多