提问人:JHen 提问时间:8/22/2023 最后编辑:JHen 更新时间:9/30/2023 访问量:100
我可以使用自定义函数从 csv 文件中提取数据吗?
Can I use a custom function to pull data from a csv file?
问:
我需要将数据从 csv 文件提取到现有的 excel 文件中。我对自定义函数和整个 excel 的更深层次机制知之甚少,因此在 GPT 3.5 的帮助下,我开发了一个自定义函数,用于从具有 2 条记录的测试 csv 文件中提取数据。
这是 GPT 给我的功能:
Function GetCSVCellValueFromRecord(csvFilePath As String, recordIndex As Long, targetColumnName As String) As Variant
Dim csvContent As String
Dim lines() As String
Dim headers() As String
Dim columnIndex As Long
Dim i As Long
' Read the entire CSV file into a string
Open csvFilePath For Input As #1
csvContent = Input$(LOF(1), 1)
Close #1
' Split the CSV content into lines
lines = Split(csvContent, vbCrLf)
' Get the headers from the first line
headers = Split(lines(0), ",")
' Find the column index of the target data
columnIndex = -1
For i = LBound(headers) To UBound(headers)
If Trim(headers(i)) = targetColumnName Then
columnIndex = i
Exit For
End If
Next i
' Return an error if the column name is not found
If columnIndex = -1 Then
GetCSVCellValueFromRecord = CVErr(xlErrValue)
Exit Function
End If
' Check if the requested record index is within bounds
If recordIndex >= 1 And recordIndex <= UBound(lines) Then
Dim fields() As String
fields = Split(lines(recordIndex), ",")
If UBound(fields) >= columnIndex Then
GetCSVCellValueFromRecord = Trim(fields(columnIndex))
Exit Function
End If
End If
' Return an error if the record or data is not found
GetCSVCellValueFromRecord = CVErr(xlErrValue)
End Function
我尝试的函数调用是:=GetCSVCellValueFromRecord(“potter.csv”,1,“time”) (csv 与工作表位于同一文件夹中) =GetCSVCellValueFromRecord(波特.csv,2,注释) 两人都回了 #Value!错误。我不确定出了什么问题,也不确定从这里该去哪里
我的最终目标是能够在字段中键入 csv 文件名,并让函数调用引用该单元格,以便使用 csv 中的信息更新所有相关字段。
答:
如果问题是您需要完整路径,但只想传入文件名,则此更改
Function GetCSVCellValueFromRecord(csvFilePath As String, recordIndex As Long, _
targetColumnName As String) As Variant
Dim csvContent As String
Dim lines() As String, headers() As String
Dim columnIndex As Long, i As Long, ff As Integer
' Read the entire CSV file into a string
ff = FreeFile 'don't use a hard-coded value...
Open ThisWorkbook.Path & "\" & csvFilePath For Input As ff
csvContent = Input$(LOF(ff), ff)
Close ff
'...etc
...只要所有 CSV 文件都位于保存带有 UDF 的工作簿的同一文件夹中,就应该执行所需的操作。
这是一个直接和具体回答 OP 问题的简单函数。
这已经在一个非常简单的 CSV 文件上进行了测试,如下所示 -
托运人 ID | 公司名称 | 电话 |
---|---|---|
1 | 快速快递 | (503) 555-9831 |
2 | 美联航套餐 | (503) 555-3199 |
3 | 联邦航运 | (503) 555-9931 |
Option Explicit
Sub sbTest()
' MsgBox NotIn("abcdef", "ab")
' MsgBox IsIn("abcdef", "ab")
' MsgBox fnGetValueCSV("s.csv", 2, "CompanyName")
' MsgBox fnGetValueCSV("s.csv", -2, "CompanyName")
MsgBox fnGetValueCSV("zz.csv", 20, "MaxCellVoltage")
End Sub
Public Function fnGetValueCSV(sCSVFileName As String, recordIndex As Long, targetColumnName As String) As Variant ' As String
' https://stackoverflow.com/questions/76947796/can-i-use-a-custom-function-to-pull-data-from-a-csv-file
' this is the spec - (csvFilePath As String, recordIndex As Long, targetColumnName As String) as Variant
' taskkill /F /IM excel.exe - kill excel.exe from the CMD line when it is in an infinite loop
' https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/split-function
' https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/cverr-function
' https://learn.microsoft.com/en-us/office/vba/excel/concepts/cells-and-ranges/cell-error-values
Dim strFileName As String
Dim iTxtFile As Integer
Dim strFileText As String
Dim zz As Long
Dim iHdrPos As Long
Dim iNumOfCommas As Long ' the number of commas to find up to the targetColumnName
Dim sComma As String
Dim iCommaPos As Long
Dim iCommaPos2 As Long
Dim arrLines() As String
sComma = ","
On Error GoTo Label_CSV_File_Name_Error
strFileName = ActiveWorkbook.Path & "\" & sCSVFileName ' CSV is in the same place as the Excel workbook.
iTxtFile = FreeFile
Open strFileName For Input As FreeFile
strFileText = Input(LOF(iTxtFile), iTxtFile)
Close iTxtFile
On Error GoTo Label_Unknown_Error
arrLines = Split(strFileText, vbCrLf) ' assumes the CSV file is perfectly formed with vbCrLf at the end of each line and nowhere else
If recordIndex < 1 Then
' line 0 is the header line, line 1 is the first data line
fnGetValueCSV = CVErr(2015) ' #VALUE!
Exit Function
End If
If NotIn(arrLines(0), targetColumnName) Then
' return #VALUE! targetColumnName not found in header line
fnGetValueCSV = CVErr(2015) ' #VALUE!
Exit Function
End If
iHdrPos = InStr(1, arrLines(0), targetColumnName) ' find the character position of the targetColumnName
iNumOfCommas = iHdrPos - Len(Replace(Mid(arrLines(0), 1, iHdrPos), sComma, "")) ' the number of commas up to the target column name
iCommaPos = 1
For zz = 1 To iNumOfCommas Step 1 ' find the character position of the comma in the data line at recordindex
iCommaPos = InStr(iCommaPos + 1, arrLines(recordIndex), sComma)
Next zz
iCommaPos2 = InStr(iCommaPos + 1, arrLines(recordIndex), sComma) ' the character position of the comma after the data we want
fnGetValueCSV = Mid(arrLines(recordIndex), iCommaPos + 1, iCommaPos2 - iCommaPos - 1) ' finally return the value in the data line
Exit Function
Label_CSV_File_Name_Error:
' return #NAME? file not found
fnGetValueCSV = CVErr(2029) ' | xlErrName | 2029 | #NAME? |
Exit Function
Label_Unknown_Error:
fnGetValueCSV = "#ERROR!" & "**" & Err.Number & "**" & Err.Description
Exit Function
End Function
Function NotIn(sText As String, sFind As String) As Boolean
If InStr(1, sText, sFind) = 0 Then
NotIn = True
Else
NotIn = False
End If
End Function
帮助程序函数 NotIn 包装该函数,使其更容易理解代码,尤其是参数的圆周方式
用于搜索文本和要查找的文本。INSTR()
如果 CSV 文件在行尾以外的任何位置都有 CRLF,则例程将不起作用。显然,它也无法处理嵌入在数据文本值中的逗号。
下面是 Excel 生成的有效 CSV 文件的示例。它具有用双引号括起来的文本,其中文本字段中有一个 CRLF,例如以“507... 它还对文本字段中出现的双引号进行了转义。例如“冷呼叫的艺术”” 带有逗号的文本字段也将用双引号括起来。
1,Davolio,Nancy,销售代表,女士,08/12/1948,01/05/1992,“507 - 20th Ave. E. Apt. 2A“,Seattle,WA,98122,USA,(206) 555-9857,5467,,”教育包括 1970 年获得科罗拉多州立大学心理学学士学位。她还完成了《冷呼叫的艺术》。Nancy 是 Toastmasters International 的成员。
评论
Sub
Debug.Print
Debug.Assert
curdir()