У меня есть файл 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





Как насчет 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
+1 это лучшее решение для такого большого набора данных, я делал это с агрегированными данными в прошлом
@Fionnuala, я использую ваш ответ для чтения файла CSV в память. Тем не менее, у меня ограничение в 280 символов, как я указал в вопросе: stackoverflow.com/questions/34230062/… Было ли у вас такое поведение и какие-либо идеи, как преодолеть это ограничение?
Это не дает прямого ответа на ваш вопрос, но grep (или один из эквивалентов Windows) действительно подходит для этого, например,
grep -e <regex_filter> foo.csv > bar.csv
Варианты grep для Windows: WinGrep (wingrep.com), PowerGrep (powergrep.com) и GNU Grep для Windows (gnuwin32.sourceforge.net/packages/grep.htm).
Учитывая, что grep доступен в той или иной форме, и вся его цель - печатать строки, соответствующие регулярному выражению, что казалось достаточным для фильтрации, упомянутой в вопросе, это казалось естественным соответствием.
Следующий код должен помочь. Передо мной нет 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
Я бы посоветовал взглянуть на библиотеку регулярных выражений (вы должны увидеть ее в «Инструменты ... Ссылки» как «Microsoft VBScript Regular Expressions 5.5» или что-то очень похожее.
Здесь есть образцы как Reg Exp, так и довольно исчерпывающий посимвольный пример: http://www.xbeat.net/vbspeed/c_ParseCSV.php. Обратите внимание, что версия Regexp намного короче!
Повеселись...
Посмотрите на инструкцию Input # в справке Excel.
Пример использования:
Input #fnInput, s_Forename, s_Surname, dt_DOB, i_Something, s_Street, s_Town, s_County, s_Postcode
а затем используйте оператор Write #, чтобы снова записать совпадающие записи
Единственная проблема может заключаться в том, что формат даты на выходе будет # 1967-07-01 #, но этот формат однозначен, в отличие от 01.07.1967, который будет представлять 1 июля в Великобритании и 7 января в США. Если вам нужно сохранить форматирование даты, запишите ее в виде строки:
s_DOB = Format(dt_DOB, "dd/mm/yyyy")
Все, что вы можете делать по очереди с помощью vba в excel, вы можете делать в доступе с помощью vba; плюс намного больше, потому что это база данных, а не электронная таблица. Вам недоступен доступ?
Работать с логическими таблицами, записями и полями намного проще, чем с логическими листами, строками и столбцами.
Почему для ввода не работает "/ Data / Import External Data / Text / csv"? Вход не действительно переносимый csv?
1,2 миллиона строк не будут работать в Excel, однако данными можно управлять с помощью ADO с помощью механизма Jet, то есть механизма, на котором основан Access. Отсюда мой ответ.
ок - итак, чтобы подтвердить - доступ недоступен? В любом случае, если вы можете получить доступ к Jet с помощью ADO, вы также можете открыть базу данных Access mdb из Excel с помощью Excel VBA и хранить там данные - вам даже не потребуется установленный Access для этого.
Я использовал следующую производную от приведенного выше кода, чтобы успешно открыть произвольный файл csv из VBA в Excel.
Option Explicit
Public cn As Connection
Public Sub DoIt()
Dim strcon As String
Dim strsql As String
Dim rs As RecordsetSet cn = CreateObject("ADODB.Connection")
strcon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=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 ' pause here to inspect objects and properties rs.Close
End Sub
Rs (набор записей) имеет набор полей со свойством Count. Каждое поле как свойство типа.
Вы можете ссылаться на поля по порядковому номеру ...
Debug.Print rs.Fields(rs.Fields.Count - 1).Type
Этого достаточно?
Если нет, опубликуйте первые несколько строк входного файла, и я займусь этим до конца.
Я использовал похожую технику, чтобы сделать то же самое в прошлом.