如果您是 VBScript 新手,您应该从一个计划(主任务、子任务、解决每个任务的想法)和一个框架 .vbs 开始编码,这样可以轻松地尝试用于解决(子任务)的方法。 )任务。
在您的情况下,主要任务是“将源文件中的坏行过滤到目标文件”。如果您可以“读取源文件的行”、“识别出错误的行”并“将它们写入目标文件”,则此任务就可以解决。
读取文件行的默认方法是:
Dim tsIn : Set tsIn = goFS.OpenTextFile("..\data\21755767.csv")
Do Until tsIn.AtEndOfStream
Dim sLine : sLine = tsIn.ReadLine()
Loop
tsIn.Close
“默认”的意思是:你必须有很好/具体的理由not选择这个习惯用法(例如:在短文件上使用 .ReadAll() 进行就地编辑或调试显示)或偏离它(例如:如果您的文件是 UTF,则不能依赖 .OpenTextFile 的默认参数-16 编码)。对于某些暴行 - 例如
Do While Not tsIn.AtEndOfStream = "False"
没有任何借口。
将(某些)行写入另一个文件应该如下所示:
Dim tsOut : Set tsOut = goFS.CreateTextFile("..\data\21755767-bads.csv")
Dim tsIn : Set tsIn = goFS.OpenTextFile("..\data\21755767.csv")
Do Until tsIn.AtEndOfStream
Dim sLine : sLine = tsIn.ReadLine()
If True Then
tsOut.WriteLine sLine
End If
Loop
tsIn.Close
tsOut.Close
使用 .CreateTextFile(JustTheFileSpec) 而不是 .OpenTextFile(lots, of, other, args) 是标准情况下最简单/清晰/错误保存的方法:每次运行脚本的新(可能是空)目标文件。
如上所述,附加一个
WScript.Echo goFS.OpenTextFile("..\data\21755767-bads.csv").ReadAll()
显示没问题。
过滤器子任务的想法基于观察:
- 标题行包含正确数量的字段/逗号
- 有问题的行包含大量逗号
然后很容易将上述工作的结果合并为:
Dim tsOut : Set tsOut = goFS.CreateTextFile("..\data\21755767-bads.csv")
Dim tsIn : Set tsIn = goFS.OpenTextFile("..\data\21755767.csv")
Dim sLine : sLine = tsIn.ReadLine()
Dim nUBSeps : nUBSeps = UBound(Split(sLine, ","))
Do Until tsIn.AtEndOfStream
sLine = tsIn.ReadLine()
If nUBSeps <> UBound(Split(sLine, ",")) Then
tsOut.WriteLine sLine
End If
Loop
tsIn.Close
tsOut.Close
完整脚本:
Option Explicit ' (1)
Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject") ' (2)
WScript.Quit demoReadFile() ' (3)
WScript.Quit demoReadWriteFile()
WScript.Quit demoFilterBads()
Function demoReadFile() ' (4)
demoReadFile = 0
Dim tsIn : Set tsIn = goFS.OpenTextFile("..\data\21755767.csv")
Do Until tsIn.AtEndOfStream
Dim sLine : sLine = tsIn.ReadLine()
WScript.Echo tsIn.Line - 1, sLine
Loop
tsIn.Close
End Function
Function demoReadWriteFile() ' (5)
demoReadWriteFile = 0
Dim tsOut : Set tsOut = goFS.CreateTextFile("..\data\21755767-bads.csv")
Dim tsIn : Set tsIn = goFS.OpenTextFile("..\data\21755767.csv")
Do Until tsIn.AtEndOfStream
Dim sLine : sLine = tsIn.ReadLine()
If True Then
tsOut.WriteLine sLine
End If
Loop
tsIn.Close
tsOut.Close
WScript.Echo goFS.OpenTextFile("..\data\21755767-bads.csv").ReadAll()
End Function
Function demoFilterBads() ' (6)
demoFilterBads = 0
Dim tsOut : Set tsOut = goFS.CreateTextFile("..\data\21755767-bads.csv")
Dim tsIn : Set tsIn = goFS.OpenTextFile("..\data\21755767.csv")
Dim sLine : sLine = tsIn.ReadLine()
Dim nUBSeps : nUBSeps = UBound(Split(sLine, ","))
Do Until tsIn.AtEndOfStream
sLine = tsIn.ReadLine()
If nUBSeps <> UBound(Split(sLine, ",")) Then
tsOut.WriteLine sLine
End If
Loop
tsIn.Close
tsOut.Close
WScript.Echo goFS.OpenTextFile("..\data\21755767-bads.csv").ReadAll()
End Function
示例输出:
演示ReadFile()
cscript 21755767.vbs
1 col1,col2,col3,col4,col5
2 1,A,AA,X,Y
3 2,B,,,CC,D
4 3,E,FF,Y,
5 4,G,,,XX,P
demoFilterBads()
cscript 21755767.vbs
2,B,,,CC,D
4,G,,,XX,P
这样的脚本可以从骨架/模板开始,例如:
Option Explicit ' (1)
Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject") ' (2)
WScript.Quit step00() ' (3)
WScript.Quit step01()
...
Function step00() ' (4)
step00 = 0
...
End Function
- 所有脚本都应以“Option Explicit”开头,以防止变量名称拼写错误
- 如果您允许全局变量,那么 goFS 是一个不错的选择。如果没有,则仅创建一个 FSO 并将其传递给需要它的子/函数/方法。Never每次需要它的方法/属性时创建一个新的 FSO。
- 使用注释或重新排序来调用您当前使用的函数
- “样本”功能;写很多来检查/阐述你的想法
更新评论:
添加实用函数:
Function qq(s) : qq = """" & s & """" : End Function
和一个实验/探索功能:
Function demoFilterSteps()
demoFilterSteps = 0
Dim sLine
For Each sLine In Split("col1,col2,col3,col4,col5 1,A,AA,X,Y 2,B,,,CC,D")
WScript.Echo 0, qq(sLine)
Dim aParts : aParts = Split(sLine, ",")
Dim nUBSeps : nUBSeps = UBound(aParts)
WScript.Echo 1, nUBSeps, qq(Join(aParts, "-"))
WScript.Echo
Next
nUBSeps = 4 ' correct
sLine = "2,B,,,CC,D" ' bad
Dim sExpr : sExpr = "nUBSeps <> UBound(Split(sLine, "",""))"
WScript.Echo 2, nUBSeps, qq(sLine), sExpr, CStr(Eval(sExpr))
End Function
output:
cscript 21755767.vbs
0 "col1,col2,col3,col4,col5"
1 4 "col1-col2-col3-col4-col5"
0 "1,A,AA,X,Y"
1 4 "1-A-AA-X-Y"
0 "2,B,,,CC,D"
1 5 "2-B---CC-D"
2 4 "2,B,,,CC,D" nUBSeps <> UBound(Split(sLine, ",")) True
To see
- 拆分标题行会导致 nUBSeps 为 4(5 个字段之间有 4 个分隔符)
- 一条好的线路也会导致 nUBSeps 为 4 - 这并不奇怪
- 坏线的 nUBSeps 不同 () 为 4;本样本中有 5 个
- 假设 nUBSeps 为 4(正确),则表达式
nUBSeps <> UBound(Split(sLine, ","))
当 sLine 持有坏行时,计算结果为 True - 因此该行应写入目标文件