2015-04-22 3 views
1

Я пытаюсь прочитать .csv для работы с ним в .accdbVBA читает CSV с разделителем в строке

Файл имеет; как разделитель и «» в качестве классификатора строк. Молодой и наивный, как и я, я просто разбить файл на разделителе:

Set oFSO = New FileSystemObject 
Set oStream = oFSO.OpenTextFile(sFilePath, ForReading) 
Do Until oStream.AtEndOfStream 
    sLine = oStream.ReadLine 
     sArray = Split(sLine, ";") 
     .... 

Теперь я получил строку:

"String";"Str;ing";0;0;0;"String" 

Так что я разделителем внутри одной из строк, что делает код выше не работает. Есть идеи, как это решить?

EDIT:

Я нашел кого-то с подобной проблемой, только с запятой в качестве разделителя. И они решили это, используя регулярные выражения. Проблема: Я не очень хорошо разбираюсь в регулярных выражениях. В этом примере используется это выражение и код:

Function regLine(sLine As String) As String 
Dim oRegEx As RegExp 
    Set oRegEx = New RegExp 
    oRegEx.IgnoreCase = True 
    oRegEx.Global = True 

    ' Pattern: ",(?=([^"]*"[^"]*")*(?![^"]*"))" 
    oRegEx.Pattern = ",(?=([^" & Chr(34) & "]*" & Chr(34) & "[^" & Chr(34) & "]*" & Chr(34) & ")*(?![^" & Chr(34) & "]*" & Chr(34) & "))" 

    regLine = oRegEx.Replace(sLine, ";") 
End Function 

Так что я не совсем понимаю выражение. Моя первая идея состояла в том, чтобы заменить запятую точкой с запятой, но это не сработало.

ответ

3
Option Explicit 

Dim line 
    line ="""String"";""Str;ing"";0;0;0;""String""" 
    WScript.Echo line 

Dim aFields 
    With New RegExp 
     .Pattern = "(""[^""]*"")?;" 
     .Global = True 
     aFields = Split(.Replace(line, "$1"&Chr(0)),Chr(0)) 
    End With 

Dim field 
    For Each field In aFields 
     WScript.Echo field 
    Next 

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

+0

Не уверен, что я сделал что-то не так, но для меня строка вывода выглядит как ;; 0; 0; 0; "String" – FNR

+0

@FNR, чтобы протестировать, скопировать код, сохранить как 'test.vbs', запустить с' cscript test.vbs' выполнить на консоли или дважды щелкнуть по файлу. Я также тестировал его как VBA в excel, заменяя 'Wcript.Echo' на' MsgBox', включая ссылку на 'Microsoft VBScript Regular Expressions' или используя' CreateObject («VBScript.RegExp») ', и в обоих случаях он работает ,Пожалуйста, включите в свой вопрос код, который вы используете, чтобы мы могли увидеть, где он может потерпеть неудачу. –

+0

'Set oRegEx = Новый RegExp oRegEx.Global = True oRegEx.Pattern =" ("" [^ ""] * "") ?; " sLine2 = oRegEx.Replace (sLine, ";") regLine = Split (sLine2, ";") ' sLine - это такая же строка, что и в моем исходном сообщении – FNR

0

Мой первый вопрос: есть ли случаи, когда ";" в строковых значениях допустимая строка? Если это так, я не вижу никакого способа, кроме ручной проверки данных.

Если нет, то насколько велик входной файл? Если он не слишком большой (для разных определений «слишком» :-)), то просто вручную сканируйте его на наличие ошибок.

Если он очень большой, я бы просто написал программу препроцессора, которая считывает строковые значения, а затем удаляет любые «;» в тех местах, где это происходит. Такая программа насчитывает всего около дюжины строк. Затем запустите чистый файл в Access.

+0

К сожалению, это очень большой файл, baout 40000 линий. Так что делать это вручную - это не вариант – FNR

+0

@ Ответ MCND доказывает, что ни пессимизм, ни ручная модификация оправданы. –

1

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

Function fixLine(sLine As String) 
Dim i As Long 
Dim bInString As Boolean 

bInString = False 
fixLine = "" 
For i = 1 To Len(sLine) 
    If Mid(sLine, i, 1) = Chr(34) Then 
     If bInString Then 
      bInString = False 
     Else 
      bInString = True 
     End If 
    End If 
    If bInString And Mid(sLine, i, 1) = ";" Then 
    Else 
     fixLine = fixLine & Mid(sLine, i, 1) 
    End If 
Next 
End Function 

Это выглядит как быстро и грязно, и я не уверен в производительности, но он работает.

EDIT: Я также работал с приведенным выше примером. Он заменяет разделитель на строку за пределами строк. Поэтому я заменил разделитель на Chr (0), который, как я знаю, не будет отображаться в строке, а затем разделится на новый разделитель.

Function regLine(sLine As String) As String() 
Dim oRegEx As RegExp 
Dim sLine2() As String 
    Set oRegEx = New RegExp 
    oRegEx.Global = True 

    'Pattern: ";(?=([^"]*"[^"]*")*(?![^"]*"))" 
    oRegEx.Pattern = ";(?=([^" & Chr(34) & "]*" & Chr(34) & "[^" & Chr(34) & "]*" & Chr(34) & ")*(?![^" & Chr(34) & "]*" & Chr(34) & "))" 

    sLine2 = oRegEx.Replace(sLine, Chr(0)) 
    regLine = Split(sLine2, Chr(0)) 
End Function 
+0

@ Ответ MCND доказывает, что не нужны грязные хаки. –

+0

Гораздо лучше, но подход и шаблон MCND по-прежнему превосходят. –

Смежные вопросы