希望excel中的VBA读取非常大的CSV,并创建CSV的一小部分的输出文件

希望excel中的VBA读取非常大的CSV,并创建CSV的一小部分的输出文件,vba,csv,excel,Vba,Csv,Excel,我有一个120万条文本记录的csv文件。字母数字字段用引号括起来,日期/时间或数字字段则不用引号括起来 比如说 “弗雷德”,“史密斯”,1967年7月1日,2,“高街7号”,“任何镇”,“任何县”,“LS1 7AA” 我想做的是在Excel中编写一些VBA(这或多或少是我唯一能够熟练使用的工具),它可以逐个记录读取CSV记录,执行检查(就像在最后一个字段,邮政编码上发生的那样),然后将1.2m记录的一小部分输出到新的输出文件 我了解如何打开这两个文件、读取记录、对数据执行所需操作并将其写出(我将

我有一个120万条文本记录的csv文件。字母数字字段用引号括起来,日期/时间或数字字段则不用引号括起来

比如说 “弗雷德”,“史密斯”,1967年7月1日,2,“高街7号”,“任何镇”,“任何县”,“LS1 7AA”

我想做的是在Excel中编写一些VBA(这或多或少是我唯一能够熟练使用的工具),它可以逐个记录读取CSV记录,执行检查(就像在最后一个字段,邮政编码上发生的那样),然后将1.2m记录的一小部分输出到新的输出文件

我了解如何打开这两个文件、读取记录、对数据执行所需操作并将其写出(我将只输出带有前缀的输入记录,前缀表示异常类型)

我不知道的是如何正确解析VBA中的CSV。我无法进行简单的文本扫描并搜索逗号,因为文本中有时会有逗号(因此文本字段以文本分隔)

是否有一个奇妙的命令可以让我快速地从记录中的第n个字段获取数据

我想要的是 s_工作=字段(s_输入_记录,5),其中5是我的CSV中的字段编号

非常感谢,,
C

VBScript如何,尽管它在Excel中也可以工作:

Set cn = CreateObject("ADODB.Connection")

'Note HDR=Yes, that is, first row contains field names '
'and FMT delimted, ie CSV '

strCon="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\Docs\;" _
& "Extended Properties=""text;HDR=Yes;FMT=Delimited"";"

cn.open strcon

'You would not need delimiters ('') if last field is numeric: '    
strSQL="SELECT FieldName1, FieldName2 INTO New.csv FROM Old.csv " _
& " WHERE LastFieldName='SomeTextValue'"

'Creates new csv file
cn.Execute strSQL

这并不能直接回答您的问题,但是
grep
(或Windows的一个等价物)确实会为此而大放异彩,例如

grep -e <regex_filter> foo.csv > bar.csv
grep-e foo.csv>bar.csv

下面的代码应该可以做到这一点。我面前没有Excel,所以我没有测试它,但这个概念是合理的

如果结果太慢,我们可以考虑提高效率的方法

Sub SelectSomeRecords()
    Dim testLine As String

    Open inputFileName For Input As #1
    Open outputFileName For Output As #2

    While Not EOF(1)
        Line Input #1, testLine
        If RecordIsInteresting(testLine) Then
            Print #2, testLine
        End If
    Wend

    Close #1
    Close #2
End Sub

Function RecordIsInteresting(recordLine As String) As Boolean
    Dim lineItems(1 to 8) As String

    GetRecordItems(lineItems(), recordLine)

    ''// do your custom checking here:
    RecordIsInteresting = lineItems(8) = "LS1 7AA"
End Function

Sub GetRecordItems(items() As String, recordLine as String)
    Dim finishString as Boolean
    Dim itemString as String
    Dim itemIndex as Integer
    Dim charIndex as Long
    Dim inQuote as Boolean
    Dim testChar as String

    inQuote = False
    charIndex = 1
    itemIndex = 1
    itemString = ""
    finishString = False

    While charIndex <= Len(recordLine)
        testChar = Mid$(recordLine, charIndex, 1)

        finishString = False

        If inQuote Then
            If testChar = Chr$(34) Then
                inQuote = False
                finishString = True
                charIndex = charIndex + 1 ''// ignore the next comma
            Else
                itemString = itemString + testChar
            End If
        Else
            If testChar = Chr$(34) Then
                inQuote = True
            ElseIf testChar = "," Then
                finishString = True
            Else
                itemString = itemString + testChar
            End If
        End If

        If finishString Then
            items(itemIndex) = itemString
            itemString = ""
            itemIndex = itemIndex + 1
        End If

        charIndex = charIndex + 1
    Wend
End Sub
Sub-SelectSomeRecords()
将测试线设置为字符串
打开inputFileName,输入为#1
打开输出文件名,输出为#2
而不是EOF(1)
线路输入#1,测试线路
如果RecordisInterest(测试线),则
打印#2,测试线
如果结束
温德
关闭#1
关闭#2
端接头
函数RecordsInterest(记录行作为字符串)作为布尔值
将行项目(1到8)调整为字符串
GetRecordItems(lineItems(),recordLine)
''//在此处进行自定义检查:
RecordIsInteresting=行项目(8)=“LS1 7AA”
端函数
子GetRecordItems(items()作为字符串,recordLine作为字符串)
Dim finishString作为布尔值
将itemString设置为字符串
Dim itemIndex为整数
暗淡的查林德克斯一样长
Dim inQuote作为布尔值
Dim testChar作为字符串
inQuote=False
charIndex=1
itemIndex=1
itemString=“”
finishString=False

虽然charIndex我建议您看看正则表达式库(您应该在“工具…参考”中看到它是“Microsoft VBScript正则表达式5.5”或类似的内容)

此位置有Reg Exp和相当全面的字符示例:。请注意,Reg Exp版本较短

玩得开心…

查看Excel帮助中的
Input#
语句

示例用法为:

Input #fnInput, s_Forename, s_Surname, dt_DOB, i_Something, s_Street, s_Town, s_County, s_Postcode
然后使用
Write#
语句再次写出匹配的记录

唯一的问题可能是输出中的日期格式最终将为#1967-07-01#,但此格式与1967年7月1日在英国表示7月1日,1月7日在美国表示不同。如果需要保留日期的格式,请将其作为字符串写出:

s_DOB = Format(dt_DOB, "dd/mm/yyyy")

您可以在excel中使用vba一行一行地执行任何操作,也可以在access中使用vba执行任何操作;此外,由于它是一个数据库而不是电子表格,您还可以执行更多操作。access对您不可用吗

处理逻辑表、记录和字段要比处理逻辑工作表、行和列容易得多


对于输入,为什么“/Data/Import External Data/Text/csv”不起作用?输入不是真正可移植的csv吗?

我使用上述代码的以下派生代码在Excel中成功地从VBA打开任意csv文件

选项显式
公共cn作为连接
公共子DoIt()
作为字符串的Dim strcon
作为字符串的Dim strsql
将遥感器作为记录集

Set cn=CreateObject(“ADODB.Connection”)

strcon=“Provider=Microsoft.Jet.OLEDB.4.0;数据源=C:\bin\HomePlanet\”。
&“扩展属性=”“text;HDR=Yes;FMT=Delimited”“

cn.开放式strcon

strsql=“从astuname.csv中选择*”
Set rs=New ADODB.Recordset
rs.打开strsql,cn
DoEvents在此处暂停以检查对象和属性 rs.Close
端接头

rs(记录集)有一个字段集合,具有Count属性。每个字段作为一个类型属性

您可以按序列号引用字段

调试。打印rs.Fields(rs.Fields.Count-1)。键入

这是否足够


如果没有,请发布输入文件的前几行,我将继续使用。

我在过去使用了类似的技术来完成同样的事情+1这是如此大的数据集的最佳解决方案,我在past@Fionnuala,我正在使用您的答案将CSV文件读入内存。但是,正如我在一个问题中指出的那样,我正在经历280个字符的限制:您是否经历过这种行为以及如何克服这种限制?grep的Windows变体:WinGrep()、PowerGrep()和GNU grep for Windows()。由于grep以某种形式提供,其全部目的是打印与正则表达式匹配的行,这似乎足以进行问题中提到的筛选,这似乎是一种自然的匹配。120万行在Excel中无法工作,但是,可以使用Jet引擎(即Access所在的引擎)使用ADO操作数据是基于的。因此我回复。确定-确认-Access不可用?无论如何,如果您可以使用ADO访问Jet,您还可以从