Replace a number in CSV file with VBscript without replacing all text - text

I'm working on this code
Dim strFirm,soNumber,strValues,arrStr,strCitrix,NewText,text
strFirm = "Gray"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("cloud.csv",1,True)
Do while not objTextFile.AtEndOfStream
arrStr = Split(objTextFile.ReadLine, ",")
If arrStr(0) = strFirm Then
soNumber = arrStr(1)
Exit Do
End If
Loop
objTextFile.Close
strCitrix = soNumber + 1
MsgBox "Cloud Client " & strFirm & " is now using " & strCitrix & " Citrix licenses."
NewText = Replace(soNumber, soNumber, strCitrix)
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("cloud.csv",2,True)
objTextFile.Writeline NewText
objTextFile.Close
However when I run the code the replacement wipes out all the text on my file with the exception of the number I'm writing.
What I want it to do is to leave all the other text in place and only change the one specified variable.
Example
Client1,5
Client2,7
Client3,12
Gray,6
Client4,9
Client5,17
Client6,8
And after running the script
Client1,5
Client2,7
Client3,12
Gray,7
Client4,9
Client5,17
Client6,8
Can anyone point out what I'm doing wrong?
Thank you in advance for your help.

Your output file contains only the number you're changing, because you extract just that number from the text you read from the file:
soNumber = arrStr(1)
increment it by one:
strCitrix = soNumber + 1
replace the number in soNumber (which contains only the number anyway) with the incremented number:
NewText = Replace(soNumber, soNumber, strCitrix)
and then write only that new number back to the file:
objTextFile.Writeline NewText
To preserve those parts of the original content that you want to keep you need to write them back to the file as well, not just the modified content.
If you read the source file line-by-line (which is a good idea when processing large files, as it avoids memory exhaustion), you should write the output to a temporary file as you go:
Set inFile = objFSO.OpenTextFile("cloud.csv")
Set outFile = objFSO.OpenTextFile("cloud.csv.tmp", 2, True)
Do while not objTextFile.AtEndOfStream
line = inFile.ReadLine
arrStr = Split(line, ",")
If arrStr(0) = strFirm Then
soNumber = CInt(arrStr(1))
outFile.WriteLine arrStr(0) & "," & (soNumber + 1)
Else
outFile.WriteLine line
End If
Loop
inFile.Close
outFile.Close
and then replace the original file with the modified one:
objFSO.DeleteFile "cloud.csv", True
objFSO.MoveFile "cloud.csv.tmp", "cloud.csv"
However, if your input file is small, it's easier to just read the entire file, process it, and overwrite the file with the modified content:
text = Split(objFSO.OpenTextFile("cloud.csv").ReadAll, vbNewLine)
For i = 0 To UBound(text)
If Len(text(i)) > 0 Then
arrStr = Split(text(i), ",")
If arrStr(0) = strFirm Then
soNumber = CInt(arrStr(1))
text(i) = arrStr(0) & "," & (soNumber + 1)
End If
End If
Next
objFSO.OpenTextFile("cloud.csv", 2, True).Write Join(text, vbNewLine)
The Len(text(i)) > 0 check is for skipping over empty lines (including a trailing newline at the end of the file), because empty strings are split into empty arrays, which would in turn make the check arrStr(0) = strFirm fail with an index out of bounds error.

For short file, I'd prefer a .ReadAll()/RegExp strategy:
Dim oFS : Set oFS = CreateObject("Scripting.FileSystemObject")
Dim sFirma : sFirma = "Gray"
Dim sFSpec : sFSpec = "..\data\cloud.csv"
Dim sAll : sAll = oFS.OpenTextFile(sFSpec).ReadAll()
Dim reCut : Set reCut = New RegExp
reCut.Global = True
reCut.Multiline = True
reCut.Pattern = "^(" & sFirma & ",)(\d+)"
Dim oMTS : Set oMTS = reCut.Execute(sAll)
If 1 = oMTS.Count Then
oFS.CreateTextFile(sFSpec).Write reCut.Replace(sAll, "$1" & (CLng(oMTS(0).SubMatches(1)) + 1))
Else
' handle error
End If
WScript.Echo oFS.OpenTextFile(sFSpec).ReadAll()
output:
Client1,5
Client2,7
Client3,12
Gray,7
Client4,9
Client5,17
Client6,8

Related

Remove double quotations using vba

I have a text file which is as below
"asdf","dfgv","asd","sdgs"
"sfgf","xcbvcvb","gsfgf","sdvxc"
"asfdfg","fbgdfg","sdfsd","fdg"
"bdg","sdf","fgfdg","fcg"
"sdf","fbcx","ckvknm","fklf"
"xv","asds","r","cxv"
But I want the output which looks like this
asdf,dfgv,asd,sdgs
sfgf,xcbvcvb,gsfgf,sdvxc
asfdfg,fbgdfg,sdfsd,fdg
bdg,sdf,fgfdg,fcg
sdf,fbcx,ckvknm,fklf
xv,asds,r,cxv
I have gone through the below link and changed the code from Write #1 to Print #1. But the problem is, I want this file to be bulk inserted to sql server. Hence, using a print doesn't help me.
Remove double quotation from write statement in vba
You can use the Replace function to strip out all the quote characters:
result = Replace(original_string, string_you_want_to_remove, replace_with )
example = Replace(original_string , CHR(34), "")
Thanks everyone, but I have found another way of removing double quotes by using the batch script which is as below.
set objRe = new RegExp
objRE.Pattern = "\"""
objRE.Global = True
strFileName = "Source.txt"
set objFS = CreateObject("Scripting.FileSystemObject")
set objTS = objFS.OpenTextFile(strFileName)
strFileContents = objTS.ReadAll
objTS.Close
strNewContents = objRE.replace(strFileContents,"")
set objWS = objFS.CreateTextFile("Results.txt")
objWS.Write StrNewContents
objWS.close
Just do a REPLACE()
Replace(<SourceString>, """, "")
Try this code:
Sub CleanFile()
Dim fileName, FSO, rfile, wfile As Variant
Dim line As String, dotAt As Integer, newFileName As String
fileName = Application.GetOpenFilename(, , "Load Excel File", , False)
If fileName = "False" Then
MsgBox "No file chosen"
Exit Sub
End If
dotAt = InStrRev(fileName, ".")
newFileName = Left(fileName, dotAt - 1) + " - CLEAN.txt"
Set FSO = CreateObject("Scripting.FileSystemObject")
Set rfile = FSO.OpenTextFile(fileName, 1) 'connection for reading
Set wfile = FSO.OpenTextFile(newFileName, 8, True, -1) 'connection for writing
Do Until rfile.AtEndOfStream
line = rfile.ReadLine
wfile.WriteLine Replace(line, """", "")
Loop
End Sub

How to take end part of a string and concat to another string?

Updating a script for efficiency. A JAL Script calls the VBScript in a loop to check each file in a txt file.
What I need help on is to take the file name, add the FormattedDT (date/time) to it (original file name is FullFileName), then copy it over to an archive folder:
\\a70tsgnaeasa001\eas\server\log\archive
For example if the file name from the txt file it is reading from is:
\\A70TSGNAEASA001\d$\EAS\Server\FIPS\BCBSFIPS.TXT
and it was last modified 10/27/2017 at 3:00, then I would want the destination to be:
\\a70tsgnaeasa001\eas\server\log\archive\BCBSFIPS_10_27_2017_03_00_00.TXT
I am having trouble figuring out how to remove the .extension, appending the date/time of the file, and then copying it to the archive folder. I put the code I have so far below.
TXT File Format:
REM there is a comment here on the first line
\\filepath1
\\filepath2
...
\\filepathN
VBScript:
option explicit
Dim SFSO, f, WSSL, FullFileName, txtFile, exitCode, txtLine, ArchiveFolder,
DateFolder, CopyFileName
Dim ArchDT, FormattedDT, mon, day, yr, hr, min, sec, FileNameArray
ArchiveFolder = "\\\\A70TSGNAEASA001\\eas\\Server\\log\\Archive\\"
Set SFSO = CreateObject("Scripting.FileSystemObject")
Set WSSL = Wscript.CreateObject("WScript.Shell")
exitCode = 0
'tests for no args
If WScript.Arguments.Count = 0 then
WScript.quit (9999)
End If
txtFile = WScript.Arguments(0)
DateFolder = ArchiveFolder&Year(Date)&"-"&Month(Date)&"-"&Day(Date)&"\\"
SFSO.CreateFolder(DateFolder)
Set f = SFSO.OpenTextFile(txtFile)
On Error Resume Next
Do Until f.AtEndOfStream
txtLine = f.ReadLine
If(Left(txtLine,2) = "\\") Then
FullFileName = txtLine
' Check for file exists
If SFSO.fileexists(FullFileName) Then
' create archive folder path
'get modified date time, format to _mm_dd_yyyy_hh_mm_ss
ArchDT = CDate(SFSO.DateLastModified(FullFileName))
mon = Month(ArchDT)
day = Day(ArchDT)
yr = Year(ArchDT)
hr = Hour(ArchDT)
min = Minute(ArchDT)
sec = Second(ArchDT)
FormattedDT = "_"&mon&"_"&day&"_"&yr&"_"&hr&"_"&min&"_"&sec
' File name with date/time appended to it
FileNameArray = Split(FullFileName, "\")
ShortFileName = FileNameArray(UBound(FileNameArray))
FileNameArray2 = Split(ShortFileName, ".")
CopyFileName =
DateFolder&FileNameArray2(0)&FormattedDT&FileNameArray2(1)
'copy file to archive folder
SFSO.CopyFile FullFileName, CopyFileName
Else
'exitCode = 9999
End If
End If
Loop
f.Close
SFSO.Close
WScript.quit(exitCode)
I've made a few changes to the code just to let it read better as you had a few typos and the like in there.
I dropped a number of the variables as you had used a couple of reserved words (Day, Empty) and rejigged the ArchiveFolder as a constant.
The rest of the code is as per yours, until the else step. At that point I get the last modified date of the file in question (you were trying to use the SFSO object for this, but the object doesn't have that method available, so I used GetFile which does.
I split the date into the date and time elements, and reformatted as per your requirements, then joined the array back together to provide the formatted date value you want to append to the filename in the archive folder.
I then split the FullFileName variable that contains the file path on the "\" character and picked out the last element, which will contain the file name.
The CopyFileName is then constructed from the ArchiveFolder, and the archive file name, with the formatted date and ".txt" suffix replacing the existing filename suffix.
Let me know if you don't understand any of what I did and I'll try to explain further.
option explicit
Dim SFSO, WSSL, FullFileName, txtFile, exitCode, txtLine, CopyFileName
Dim ArchDT, FormattedDT, fileName, tempArray
Const ArchiveFolder = "\\A70TSGNAEASA001\eas\Server\log\Archive\"
Set SFSO = CreateObject("Scripting.FileSystemObject")
Set WSSL = Wscript.CreateObject("WScript.Shell")
exitCode = 0
'tests for no args
If WScript.Arguments.Count = 0 then
WScript.quit (9999)
End If
txtFile = WScript.Arguments(0)
Set f = SFSO.OpenTextFile(txtFile)
On Error Resume Next
Do Until f.AtEndOfStream
txtLine = f.ReadLine
If(Left(txtLine,2) == "\\")
FullFileName = txtLine
' Check for file exists
If SFSO.fileexists(FullFileName) then
' Check file status
If VarType(SFSO.OpenTextFile(FullFileName,8,False)) = vbError Then
exitCode = 9999
Else
ArchDT = oFso.GetFile(FullFileName).DateLastModified
'get modified date time, format to _mm_dd_yyyy_hh_mm_ss
tempArray = Split(ArchDT, " ") ' gives us an array with date and time in two elements
tempArray(0) = Right("0" & Month(ArchDT),2) & "_" & Right("0" & Day(ArchDT), 2) & "_" & Year(ArchDT)
tempArray(1) = Replace(tempArray(1), ":", "_")
FormattedDT = Join(tempArray, "_") ' now have the formatted date value
' Get the filename
tempArray = Split(FullFileName, "\")
fileName = tempArray(UBound(tempArray)) ' filename is the last element in this array
' File name with date/time appended to it
'Part I'm having trouble with
CopyFileName = ArchiveFolder & Replace(fileName, ".txt", FormattedDT & ".txt")
'copy file to archive folder (how I would copy the file)
SFSO.CopyFile(FullFileName, CopyFileName)
End If
Else
exitCode = 9999
End If
End If
Loop
f.Close
Err.Clear
SFSO.Close
WScript.quit(exitCode)

How to create a file with contents based on files in a directory

I have an existing xls file which creates a CONTENTS file based on the files in a directory. For example, if a directory contains file.pdf and file.txt, it will create a file with contents
file.pdf
file.txt
with each file separated by a line break.
What I would like to do is that I want the contents to contain
file.pdf bundle:ORIGINAL
file.txt bundle:TEXT
file.pdf and bundle:ORIGINAL is separated by a tab character. The directory will contain these 2 filetypes, 1 pdf and 1 text file. So basically, what I want is that for every pdf file, it should be followed by bundle:ORIGINAL text while if its a text file, it should be followed by bundle:TEXT.
The original code is below:
For i = 2 To lRows
If Trim(Cells(i, 1).Value) = "" Then Exit For
' create the CONTENTS file
FileList = GetFileList(oDirectory & "\" & Trim(Cells(i, lCols).Value) & "\")
cFileNum = FreeFile
ContentsPath = oDirectory & "\" & Trim(Cells(i, lCols).Value) & "\" & "contents"
Open ContentsPath For Output As #cFileNum
For k = 1 To UBound(FileList)
If (FileList(k) <> "contents" And FileList(k) <> "dublin_core.xml") Then
Print #cFileNum, FileList(k)
End If
Next k
Close #cFileNum
EDIT
This is the Function GetFileList
Function GetFileList(FileSpec As String) As Variant
' Returns an array of filenames that match FileSpec
' If no matching files are found, it returns False
Dim FileArray() As Variant
Dim FileCount As Integer
Dim FileName As String
On Error GoTo NoFilesFound
FileCount = 0
FileName = Dir(FileSpec)
If FileName = "" Then GoTo NoFilesFound
' Loop until no more matching files are found
Do While FileName <> ""
FileCount = FileCount + 1
ReDim Preserve FileArray(1 To FileCount)
FileArray(FileCount) = FileName
FileName = Dir()
Loop
GetFileList = FileArray
Exit Function
' Error handler
NoFilesFound:
GetFileList = False
End Function
Please note that I am obviously not the author of this code, I just downloaded this excel file (the site no longer exists) a long time ago and I just need to tweak this for my own use.
Thanks in advance.
Something like this should do it:
'...
If (FileList(k) <> "contents" And FileList(k) <> "dublin_core.xml") Then
Print #cFileNum, FileList(k) & vbTab & GetType(Cstr(FileList(k)))
End If
'...
Function:
Function GetType(fName as string)
Dim rv As String
Select Case Right(Ucase(fName),3)
Case "TXT": rv = "bundle:TEXT"
Case "PDF": rv = "bundle:ORIGINAL"
End Select
GetType = rv
End Function

Reading International/Special Characters in VBA

I read an Excel spreadsheet row by row and for each row create a textfile including information from the columns.
From time to time there is foreign text in some of the spreadsheet cells. In the debugger the foreign text appears as '?' question marks. It fails when trying to write these question marks to the text file.
This is a snippet of the code that reads the values from a row to a string array
Set oFS = CreateObject("Scripting.Filesystemobject")
For Each rID In oSh.UsedRange.Columns("A").Cells
For Each rValue In oSh.UsedRange.Rows(rowCount).Cells
ReDim Preserve columnValues(columnCount)
columnValues(columnCount) = rValue
columnCount = columnCount + 1
Next
Next
This is the code which writes to a text file
sFNText = sMakeFolder & "\" & rID.Value & ".txt"
Set oTxt = oFS.OpenTextFile(sFNText, 2, True)
For i = 0 To UBound(columnTitles)
oTxt.Write columnTitles(i) & ": " & columnValues(i) & vbNewLine
Next i
oTxt.Close
I have experimented with changing the format of opentextfile and also using AscW and ChrW to convert to and from ansi.
EDIT: In particular I am trying to read in Greek symbols (pi, omega etc.) and write them back out to a textfile. I have used the
StrConv(Cells(1, 1), vbUnicode)
method that was detailed in How can I create text files with special characters in their filenames and have got that example working. It seems now a problem with writing this to a textfile. nixda's example seems to work in isolation when using his Print command, however when I try
otxt.Write
to write my stored variable to a textfile it writes out garbage, as opposed to the print method which produces the correct result. Looking at the debugger both variables are stored identically (print method + write), so I believe it is now down to the output method (otxt.Write) which is converting the stored variable into garbage. I have tried using the -1 & -2 options for OpenTextFile - both producing garbage results.
I have the following sheet:
and the following code:
Sub writeUnicodeText()
Dim arr_Strings() As String
i = 0
For Each oCell In ActiveSheet.Range("A1:A4")
ReDim Preserve arr_Strings(i)
arr_Strings(i) = oCell.Value
i = i + 1
Next
Set oFS = CreateObject("Scripting.Filesystemobject")
Set oTxt = oFS.OpenTextFile("C:\users\axel\documents\test.txt", 2, True, -1)
For i = 0 To UBound(arr_Strings)
oTxt.Write arr_Strings(i) & vbNewLine
Next i
oTxt.Close
End Sub
This produces the following file:
This is the code I use to write to a text. I've tried many methods and this has worked the best.
Sub ProcessX()
FName1 = "Location of File"
txtStrngX = OpenTextFileToString2(FName1)
end sub
Public Function OpenTextFileToString2(ByVal strFile As String) As String
Dim hFile As Long
hFile = FreeFile
Open strFile For Input As #hFile
OpenTextFileToString2 = Input$(LOF(hFile), hFile)
Close #hFile
End Function
As for reading in from rows just be sure to set your variable to a string when compiling and any method should work fine.
sorry. That's reading from a text. Here is writing.
Public Function RecordsetToText(rs As Object, Optional FullPath _
As String, Optional ValueDelimiter As String = " ") As Boolean
'PURPOSE: EXPORTS DATA FROM AN ADO RECORDSET TO A TEXT FILE
'PARAMETERS:
'RS: Recordset to Export. Open the recordset before
'passing it to this function
'FullPath (Optional): FullPath of text file.
'if not specified, the function uses app.path +
'rs.txt
'ValueDelmiter (Optional): String to delimiter
'values within a row. If not specified, an tab
'is used
'RETURNS: True if successful, false if an error occurs
'COMMENTS: Rows are delimited by a carriage return
Dim sFullPath As String
Dim sDelimiter As String
Dim iFileNum As Integer
Dim lFieldCount As Long
Dim lCtr As Long
Dim oField As ADODB.Field
On Error GoTo ErrorHandler:
If RecordSetReady(rs) = False Then Exit Function
sDelimiter = ValueDelimiter
If FullPath = "" Then
sFullPath = App.Path
If Right(sFullPath, 1) <> "\" Then sFullPath = _
sFullPath & "\"
sFullPath = sFullPath & "rs.txt"
Else
sFullPath = FullPath
End If
iFileNum = FreeFile
Open sFullPath For Output As #iFileNum
With rs
lFieldCount = .Fields.Count - 1
On Error Resume Next
.MoveFirst
On Error GoTo ErrorHandler
For lCtr = 0 To lFieldCount
Set oField = .Fields(lCtr)
If lCtr < lFieldCount Then
Print #iFileNum, oField.Name & sDelimiter;
Else
Print #iFileNum, oField.Name
End If
Next
Do While Not .EOF
For lCtr = 0 To lFieldCount
Set oField = .Fields(lCtr)
If lCtr < lFieldCount Then
Print #iFileNum, oField.Value & sDelimiter;
Else
Print #iFileNum, oField.Value
End If
Next
.MoveNext
Loop
End With
RecordsetToText = True
ErrorHandler:
On Error Resume Next
Close #iFileNum
End Function

Remove a line from a text file if that line contains some string

In VB6, I'm looking for a way to remove a line of text from a text file if that line contains some string. I work mostly with C# and I'm at a loss here. With .NET there are several ways to do this, but I'm the lucky one who has to maintain some old VB code.
Is there a way to do this?
Thanks
Assuming you have the filename in a variable sFileName:
Dim iFile as Integer
Dim sLine as String, sNewText as string
iFile = FreeFile
Open sFileName For Input As #iFile
Do While Not EOF(iFile)
Line Input #iFile, sLine
If sLine Like "*foo*" Then
' skip the line
Else
sNewText = sNewText & sLine & vbCrLf
End If
Loop
Close
iFile = FreeFile
Open sFileName For Output As #iFile
Print #iFile, sNewText
Close
You may want to output to a different file instead of overwriting the source file, but hopefully this gets you closer.
Well text files are a complicated beast from some point of view: you cannot remove a line and move the further text backward, it is a stream.
I suggest you instead about considering an input to output approach:
1) you open the input file as text
2) you open a second file for output, a temporary file.
3) you iterate through all lines in file A.
4) if current line contains our string, don't write it. If current line does not
contains our string, we write it in the file B.
5) you close file A, you close file B.
Now you can add some steps.
6) Delete file A
7) Move file B in previous file A location.
DeleteLine "C:\file.txt", "John Doe", 0,
Function DeleteLine(strFile, strKey, LineNumber, CheckCase)
'Use strFile = "c:\file.txt" (Full path to text file)
'Use strKey = "John Doe" (Lines containing this text string to be deleted)
Const ForReading = 1
Const ForWriting = 2
Dim objFSO, objFile, Count, strLine, strLineCase, strNewFile
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(strFile, ForReading)
Do Until objFile.AtEndOfStream
strLine = objFile.Readline
If CheckCase = 0 Then strLineCase = UCase(strLine): strKey = UCase(strKey)
If LineNumber = objFile.Line - 1 Or LineNumber = 0 Then
If InStr(strLine, strKey) Or InStr(strLineCase, strKey) Or strKey = "" Then
strNewFile = strNewFile
Else
strNewFile = strNewFile & strLine & vbCrLf
End If
Else
strNewFile = strNewFile & strLine & vbCrLf
End If
Loop
objFile.Close
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(strFile, ForWriting)
objFile.Write strNewFile
objFile.Close
End Function

Resources