Хотите, чтобы VBA в Excel читал очень большой CSV и создавал выходной файл из небольшого подмножества CSV - PullRequest
11 голосов
/ 09 января 2009

У меня есть файл CSV 1,2 миллиона записей текста. Буквенно-цифровые поля заключены в кавычки, а поля даты / времени или числовые - нет.

Например "Фред", "Смит", 01.07.1967,2, "7, Хай-стрит", "Anytown", "Anycounty", "LS1 7AA"

Что я хочу сделать, так это написать какой-нибудь VBA в Excel (более или менее единственный доступный мне инструмент, которым я достаточно опытен в использовании), который читает запись CSV по записи, выполняет проверку (как это происходит на последнее поле (почтовый индекс), а затем выводит небольшое подмножество записей длиной 1,2 м в новый выходной файл.

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

Чего я не знаю, так это как правильно проанализировать CSV в VBA. Я не могу выполнить простое сканирование текста и искать запятые, поскольку в тексте иногда есть запятые (поэтому текстовые поля разделены текстом)

Есть ли фантастическая команда, которая позволила бы мне быстро получить данные из n-го поля моей записи?

То, что я хочу, это s_work = field (s_input_record, 5) где 5 - номер поля в моем CSV ....

Большое спасибо, C

Ответы [ 7 ]

8 голосов
/ 09 января 2009

Следующий код должен помочь. Передо мной нет 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
7 голосов
/ 09 января 2009

Как насчет 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
4 голосов
/ 09 января 2009

Это не дает прямого ответа на ваш вопрос, но grep (или один из эквивалентов Windows) действительно бы блестел, например,

grep -e <regex_filter> foo.csv > bar.csv
3 голосов
/ 10 января 2009

Я использовал следующую производную кода, приведенного выше, чтобы успешно открыть произвольный CSV-файл из VBA в Excel.

Параметр Явный
Public cn As Connection
Public Sub DoIt ()
Dim Strcon As String
Dim strsql As String
Dim rs As Recordset

Set cn = CreateObject ("ADODB.Connection")

strcon = "Provider = Microsoft.Jet.OLEDB.4.0; Источник данных = C: \ bin \ HomePlanet \;" _
& "Extended Properties =" "text; HDR = Yes; FMT = Delimited" ";"

cn.Open strcon

strsql = "SELECT * FROM astuname.csv"
Set rs = New ADODB.Recordset
rs.Open strsql, cn
Пауза DoEvents здесь, чтобы проверить объекты и свойства rs.Close
End Sub

rs (набор записей) имеет коллекцию полей со свойством Count. Каждое поле как свойство типа.

Вы можете ссылаться на поля по порядковому номеру ...

Debug.Print rs.Fields (rs.Fields.Count - 1). Тип

Достаточно ли этого?

Если нет, опубликуйте первые несколько строк входного файла, а я возьму его до конца.

2 голосов
/ 10 января 2009

Все, что вы можете делать построчно с помощью vba в excel, вы можете делать с доступом с помощью vba; плюс намного больше, потому что это база данных, а не электронная таблица. Вам недоступен доступ?

Работать с логическими таблицами, записями и полями намного проще, чем с логическими таблицами, строками и столбцами.

Для ввода, почему «/ Data / Import External Data / Text / csv» не работает? Разве вход не является действительно переносимым csv?

2 голосов
/ 10 января 2009

Посмотрите на оператор Input # в справке Excel

Пример использования будет:

Input #fnInput, s_Forename, s_Surname, dt_DOB, i_Something, s_Street, s_Town, s_County, s_Postcode

, а затем используйте оператор Write # для повторной записи соответствующих записей

Единственная проблема может заключаться в том, что формат даты в выходных данных будет иметь вид # 1967-07-01 #, но этот формат однозначен в отличие от 07.07.1967, который будет представлять 1 июля в Великобритании и 7 января в НАС. Если вам нужно сохранить форматирование даты, запишите ее в виде строки:

s_DOB = Format(dt_DOB, "dd/mm/yyyy")
1 голос
/ 09 января 2009

Я бы посоветовал взглянуть на библиотеку регулярных выражений (вы должны увидеть ее в «Инструменты ... Ссылки» как «Регулярные выражения Microsoft VBScript 5.5» или что-то очень похожее.

В этом месте есть образцы как Reg Exp, так и довольно подробного посимвольного символа: http://www.xbeat.net/vbspeed/c_ParseCSV.php. Обратите внимание, что версия Regexp стала намного короче!

Веселись ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...