Given: I recorded a simple macro in Openoffice to save my worksheet as a CSV file. Here it is.
sub toCSV
dim document as object
dim dispatcher as object
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
dim args1(2) as new com.sun.star.beans.PropertyValue
args1(0).Name = "URL"
args1(0).Value = "file:///path/csv/filename.csv"
args1(1).Name = "FilterName"
args1(1).Value = "Text - txt - csv (StarCalc)"
args1(2).Name = "FilterOptions"
args1(2).Value = "59,34,76,1"
dispatcher.executeDispatch(document, ".uno:SaveAs", "", 0, args1())
end sub
Problem: I want to add some features to this function. 1. I need to get the current XLS filename so that I can put that at the end of my static path. So file:///path/csv/ is going to always remain the same, and filename.csv will be coming from filename.xls. 2. Well, I'll need to do some regex replacement on that filename-revision01.xls to ultimately get filename.csv.
I can do regex matching well, I'm simply looking for hints on string concatenation, how to get the current filename, and how to write a regex expression within a macro.
BTW, what is this language called!?
This is the solution I came up with to help in exporting a CSV (with my export options, filename adjustment, and file location) with one click.
I'm on a Mac, so the file paths will be for such an operating system. The information that helped me do this is here.
REM ***** BASIC *****
sub toCSV
dim document as object
dim dispatcher as object
document = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
FileURL = ThisComponent.URL
oMasterScriptProviderFactory = createUnoService("com.sun.star.script.provider.MasterScriptProviderFactory")
oMasterScriptProvider = oMasterScriptProviderFactory.createScriptProvider("")
oScriptReplace = oMasterScriptProvider.getScript("vnd.sun.star.script:Tools.Regex.js?language=JavaScript&location=user")
sReturn = RegExpReplace(oScriptReplace, FileURL, "(.*)/(\w*-\w*)(-revision\d*)+\.xls", "i", "$2.csv")
dim args1(2) as new com.sun.star.beans.PropertyValue
args1(0).Name = "URL"
args1(0).Value = "file:///Users/joe/Documents/mydocuments/trunk/my%20projects/dictionary/verbsXLS/proofed/csv/" + sReturn
args1(1).Name = "FilterName"
args1(1).Value = "Text - txt - csv (StarCalc)"
args1(2).Name = "FilterOptions"
args1(2).Value = "59,34,76,1"
dispatcher.executeDispatch(document, ".uno:SaveAs", "", 0, args1())
end sub
function RegExpReplace(oScriptReplace as Object, sSource as String, sRegExp as String, sGlobUpcase as String, sReplace as String) as String
RegExpReplace = oScriptReplace.invoke(Array(sSource, sRegExp, sGlobUpcase, sReplace ), Array(), Array())
end function
Here is a bit of javascript that the above macro relies upon. This file is named ~/Library/Application\ Support/OpenOffice.org/3/user/Scripts/javascript/Tools/Regex.js and is hardcoded and referenced above.
sSource = String(ARGUMENTS[0])
sRegExp = String(ARGUMENTS[1])
sGlobUpcase = (ARGUMENTS[2])
sReplace = String(ARGUMENTS[3])
myRe = new RegExp(sRegExp, sGlobUpcase)
ret = sSource.replace(myRe, sReplace)
Finally, this post gives details on how to add a toolbar button to run your macro with one click.
Related
I am old and used to older VBA in Excel and Older VB code. Now I am trying to work in Visual Studio Community with VB. I have looked for help but everything I find for .NET comes up with C++ or C# code which I don't follow. I haven't even been able to find a book to help converting to the newer format of code. I am used to;
Dim outpath as integer
Dim aString as String
Dim aDouble as Double
aString = "Some Text"
aDouble = 3.1429
outpath = FreeFile
Open "C:\afolder\somedata.dat" For Output As outpath
print #outpath, aString
print #outpath, aDouble
close #outpath
To read data I'm used to using the aString = input #outpath instructions.
From what I have read it appears I should be using IO.Stream functions but have not found anything that would replicate the old method I am used to above.
Can somebody please point me to some internet pages that cover this in VB rather than falling into C code which I cannot translate to VB.
Thank you kindly.
Sure, there are a number of ways to do this. I also came from VB6, and lots of VBA.
So, to convert your above, and to write out to a file?
Well, one apporach (and we even did this in VBA) was to create a string, concentante the values to the string, and then write the string out to a file.
It is easy, but you have to in code toss in the next line character.
So, this will work:
Dim aString As String
Dim aDouble As Double
aString = "Some Text"
aDouble = 3.1429
Dim strPath As String = "C:\test\somedata.dat"
Dim strOutBuf As String = ""
strOutBuf = aString
strOutBuf = strOutBuf & vbCrLf & aDouble
File.WriteAllText(strPath, strOutBuf)
So, for a few easy lines of text - very easy.
However, for a lot of code, and a line by line output - similar to VBA?
Then you do it this way:
Dim FILE_NAME As String = "C:\test\test2.txt"
Dim MyFileWriter As New StreamWriter(FILE_NAME)
Dim aString As String
Dim aDouble As Double
aString = "Some Text"
aDouble = 3.1429
MyFileWriter.WriteLine(aString)
MyFileWriter.WriteLine(aDouble)
For i = 1 To 10
MyFileWriter.WriteLine(i)
Next
MyFileWriter.Close()
Note that in above, the file does not (can not) already exist.
So, you have to deal with that issue.
You can either delete the file before you start writing.
eg:
Dim FILE_NAME As String = "C:\test\test2.txt"
If File.Exists(FILE_NAME) Then
File.Delete(FILE_NAME)
End If
(and then the rest of your code follows. So there no need (or concept) of FreeFile() anymore.
output:
Some Text
3.1429
1
2
3
4
5
6
7
8
9
10
Edit: --------------------------------
Well, showing how to write out a file is kind of like the hug, without the kiss. So, now, how can we read the file?
Well, it really depends on what we want to do with that input. But .net tends to work reading (or in fact writing) the whole thing in one shot.
But, a line by line read would look like this:
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim FILE_NAME As String = "C:\test\test2.txt"
Dim MyFileReader As New StreamReader(FILE_NAME)
Do While MyFileReader.EndOfStream = False
Debug.Print("one line of file = " & MyFileReader.ReadLine)
Loop
MyFileReader.Close()
End Sub
output:
one line of file = Some Text
one line of file = 3.1429
one line of file = 1
one line of file = 2
one line of file = 3
one line of file = 4
one line of file = 5
one line of file = 6
one line of file = 7
one line of file = 8
one line of file = 9
one line of file = 10
' vb.net has allowed declaration and assignment on the same line for more than 20yrs now
Dim aString as String = "Some Text"
Dim aDouble as Double = 3.1429
' New API methods do not use integers to track files.
' That was always kind of weird.
Dim outpath As String = "C:\afolder\somedata.dat"
' StreamReader/StreamWriter are great, and you should learn them,
' but you don't need them for this sample
System.IO.File.WriteAllText(outpath, $"{aString}{vbCrLf}{aDouble}")
' Interpolated strings (like above) are kind of fun, too
Again, without the comments and assuming an Imports directive for System.IO, to highlight how simple this can be:
Dim aString as String = "Some Text"
Dim aDouble as Double = 3.1429
Dim outpath As String = "C:\afolder\somedata.dat"
File.WriteAllText(outpath, $"{aString}{vbCrLf}{aDouble}")
If the interpolated string is too confusing, here's one more option:
Dim aString as String = "Some Text"
Dim aDouble as Double = 3.1429
Dim outpath As String = "C:\afolder\somedata.dat"
File.WriteAllText(outpath, aString)
File.AppendAllText(outpath, aDouble.ToString("r"))
However, that actually opens, writes, and closes the file twice. It's extra I/O, which is some of the slowest stuff you can do in a computer, so I don't recommend it.
Instead, you could build the output string with concatenation, but I'm sure you're aware that can also be cumbersome, so here's a final alternative with a System.IO.StreamWriter:
Dim aString as String = "Some Text"
Dim aDouble as Double = 3.1429
Dim outpath As String = "C:\afolder\somedata.dat"
'Using blocks (added way back in 2005) replace the need to Close the file
' Moreover, they promise to dispose of the file handle
' **even if there's an exception/error**,
' making your code safer and better.
Using writer As New StreamWriter(outpath)
writer.WriteLine(aString)
writer.WriteLine(aDouble)
End Using
Then to read the values back:
Dim filePath As String = "C:\afolder\somedata.dat"
Dim aString as String
Dim aDouble as Double
Using reader As New StreamReader(filePath)
aString = reader.ReadLine()
aDouble = Double.Parse(reader.ReadLine())
End Using
I am trying to go through my text file and create a new file that will contain only the text I require. My current line looks like:
Car-1I
Colour-39
Cost-328
Dealer-28
Car-2
Colour-30
Cost-234
For each block of text I would like to read the first line, if the first line ends with an I, then read the next line, if that line contains a colour 39, then I would like to save the whole block of text to another file. If these two conditions aren't met, I dont want to save my values to the new text file.
Before anything about saving my values in classes are mentioned, these blocks of text can vary in size and values, so I dont always have a set range of values which is why i need to skip to the blank line
IO.File.WriteAllText("C:\Users\test2.txt", "") 'write to new file
Dim sKey As String
Dim sValue As Integer
For Each filterLine As String In File.ReadLines("C:\Users\test.txt")
sKey = Split(filterLine, ":")(0)
sValue = Split(filterLine, ":")(1)
If Not sValue.EndsWith("I") Then
ElseIf sValue.EndsWith("I") Then
End If
Next
Another method, using File.ReadLines to read lines of text from file. This method doesn't load all the text in memory, it reads from disc single lines of text, so it can also be useful when dealing with big files.
You could loop the IEnumerable collection it returns, but also use its GetEnumerator() method to control more directly when to move to the next line, or move more then one lines forward.
Its Enumerator.Current object returns the line of text currently read, Enumerator.MoveNext() moves to the next line.
A StringBuilder is used to store the strings when a match found. Strings are added to the StringBuilder object using its AppendLine() method.
This class is useful when dealing with strings that you need to store, compare and discard (or modify) quickly: since string are immutable, when you use String variables directly, especially in loops, you generate a whole lot of garbage that slows down any procedure quite a lot.
The blocks of text stored in the StringBuilder object are then written to a destination file using a StreamWriter with explicit encoding set to UTF-8 (writes the BOM). Its methods include asynchronous versions: WriteLine() can be replaced by awaitWriteLineAsync() to allow an async procedure.
Imports System.IO
Imports System.Text
Dim sourceFilePath = "<Path of the source file>"
Dim resultsFilePath = "<Path of the destination file>"
Dim sb As New StringBuilder()
Dim enumerator = File.ReadLines(sourceFilePath).GetEnumerator()
Using sWriter As New StreamWriter(resultsFilePath, False, Encoding.UTF8)
While enumerator.MoveNext()
If enumerator.Current.EndsWith("I") Then
sb.AppendLine(enumerator.Current)
enumerator.MoveNext()
If enumerator.Current.EndsWith("39") Then
While Not String.IsNullOrWhiteSpace(enumerator.Current)
sb.AppendLine(enumerator.Current)
enumerator.MoveNext()
End While
sWriter.WriteLine(sb.ToString())
End If
sb.Clear()
End If
End While
End Using
This will work:
Dim strFile As String = "c:\Test5\Source.txt"
Dim strOutFile As String = "c:\Test5\OutPut.txt"
Dim strOutData As String = ""
Dim SourceGroups As String() = Split(File.ReadAllText(strFile), vbCrLf + vbCrLf)
For Each sGroup As String In SourceGroups
Dim OneGroup() As String = Split(sGroup, vbCrLf)
If Strings.Right(OneGroup(0), 1) = "I" And (Strings.Right(OneGroup(1), 2) = "39") Then
If strOutData <> "" Then strOutData += (vbCrLf & vbCrLf)
strOutData += sGroup
End If
Next
File.WriteAllText(strOutFile, strOutData)
Something like this should work:
Dim base, i, c as Integer
Dim lines1$() = File.ReadLines("C:\Users\test.txt")
c = lines1.count
While i < c
if Len(RTrim(lines1(i))) Then
If Strings.Right(RTrim(lines1(i)), 1)="I" Then
base = i
i += 1
If Strings.Right(RTrim(lines1(i)), 2)="39" Then
While Len(RTrim(lines1(i))) 'skip to the next blank
i += 1
End While
' write lines1(from base to (i-1)) here
Else
While Len(RTrim(lines1(i)))
i += 1
End While
End If
Else
i += 1
End If
Else
i += 1
End If
End While
This is a follow on question to a post I made. Append one file into another file
I need to search the master document for entities "&CH1.sgm" to "&CH33.sgm",
mark where they are in the master document and replace the entity call with the matching file "Chapter1.sgm" found in "fnFiles". I can change the file names and entities to anything if that will help.
My code copies the text of a file and appends it to the bottom of the master_document.sgm. But now I need it to be more intelligent. Search the Master document for entity markers, then replace that entity marker with that file contents match. The file number and entity number match up. e.g.(&CH1; and Bld1_Ch1.sgm)
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
Dim searchDir As String = txtSGMFile.Text 'Input field from form
Dim masterFile = "Bld1_Master_Document.sgm"
Dim existingFileMaster = Path.Combine(searchDir, masterFile)
'Read all lines of the Master Document
Dim strMasterDoc = File.ReadAllText(existingFileMaster) '// add each line as String Array.
'?search strMasterDoc for entities &Ch1.sgm
'?replace entity name "&Ch1.sgm" with content of file "Bld1_Ch1.sgm" this content if found below
'? do I use a book mark? Replace function?
'Get all the sgm files in the directory specified
Dim fndFiles = Directory.GetFiles(searchDir, "*.sgm")
'Set up the regular expression you will make as the condition for the file
Dim rx = New Regex(".*_Ch\d\.sgm")
Dim ch1 = New Regex(".*_Ch[1]\.sgm")
'Use path.combine for concatenatin directory together
'Loop through each file found by the REGEX
For Each fileNo In fndFiles
If rx.IsMatch(fileNo) Then
If ch1.IsMatch(fileNo) Then
Dim result = Path.GetFileName(fileNo)
'Use path.combine for concatenatin directory together
Dim fileToCopy = Path.Combine(searchDir, result)
'This is the file we want to copy into MasterBuild but at specific location.
'match &ch1.sgm inside strMasterDoc
Dim fileContent = File.ReadAllText(fileToCopy)
'Search master file for entity match then append all content of fileContent
File.AppendAllText(existingFileMaster, fileContent)
MessageBox.Show("File Copied")
End If
End If
Next
Close()
End Sub
If I understand correctly (big if), you want to replace the the text of the abbreviated chapter name in the master file with the contents of the file it refers to at the spot where the abbreviation is found.
I made a class to handle the details.
Private Sub btnImport_Click(sender As Object, e As EventArgs) Handles btnImport.Click
'Add a FolderBrowseDialog to your form designer
FolderBrowserDialog1.ShowDialog()
Dim searchDir As String = FolderBrowserDialog1.SelectedPath
Dim existingFileMaster = Path.Combine(searchDir, "Bld1_Master_Document.sgm")
Dim lstFileChanges = CreateList(searchDir)
'The following method does NOT return an array of lines
Dim strMasterDoc = File.ReadAllText(existingFileMaster)
For Each fc In lstFileChanges
strMasterDoc = strMasterDoc.Replace(fc.OldString, fc.NewString)
Next
File.WriteAllText(existingFileMaster, strMasterDoc)
End Sub
Private Function CreateList(selectedPath As String) As List(Of FileChanges)
Dim lstFC As New List(Of FileChanges)
For i = 1 To lstFC.Count
Dim fc As New FileChanges
fc.OldString = $"&CH{i}.sgm"
fc.FileName = $"Chapter{i}.sgm"
fc.NewString = File.ReadAllText(Path.Combine(selectedPath, fc.FileName))
lstFC.Add(fc)
Next
Return lstFC
End Function
Public Class FileChanges
Public Property OldString As String '&CH1.sgm
Public Property FileName As String 'Chapter1.sgm
Public Property NewString As String 'Contents of Chapter1.sgm, the string to insert
End Class
Testing .Replace
Dim s As String = "The quick brown fox jumped over the lazy dogs."
s = s.Replace("fox", "foxes")
MessageBox.Show(s)
I am making a media player application using AXWMPlib which has a playlist.
what i successfully able to do was saving the playlist items in a text file.
below is the code for saving:
If SavePlaylist.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim writefile As New System.IO.StreamWriter(SavePlaylist.FileName)
For i = 0 To lstview.Items.Count - 2
writefile.WriteLine(Form1.main.AxWMP1.currentPlaylist.Item(i).sourceURL)
Next
writefile.Write(Form1.main.AxWMP1.currentPlaylist.Item(Form1.main.AxWMP1.currentPlaylist.count - 1).sourceURL)
writefile.Close()
End If
for loading i wrote till here:
If OpenPlaylist.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim readfile As New System.IO.StreamReader(OpenPlaylist.FileName)
Dim ob As String = readfile.ReadToEnd()
Dim content() As String = OpenPlaylist.FileName.Split(Environment.NewLine)
End If
i dont know how to read the lines stored in current() and append them in current playlist.
found a solution:
If Open.ShowDialog = Windows.Forms.DialogResult.OK Then
Dim readfile As New System.IO.StreamReader(Open.FileName)
Dim ob As String = readfile.ReadToEnd()
Dim content() As String = ob.Split(Environment.NewLine)
For Each Line As String In content
Dim item As IWMPMedia = Form1.AxWMP1.newMedia(Line)
Form1.AxWMP1.currentPlaylist.appendItem(item)
Next
End If
I have if condition issues when running the following code for an image file:
Dim mainFolder As String = "\\Users\No_Image_Available.png"
Dim saveDirectory As String = "\\IMAGE\"
Dim Filename As String = System.IO.Path.GetFileName(mainFolder)
Dim mainSavePath As String = System.IO.Path.Combine(saveDirectory, Filename)
If System.IO.File.Exists(mainSavePath) Then
'do nothing
Else
'file doesn't exist
My.Computer.FileSystem.CopyFile("\\Users\No_Image_Available.png", "\\IMAGES\No_Image_Available.png")
End If
If the file doesn't exist then it will accept the if statements by either IF Not exist or IF exist... however, if the file already exist it will take the copy argument whether it is in the right if condition or not.
Why is that? It is as if it still reads and accepts the first 'do nothing' condition regardless.
FYI- the paths you see are fake
Issue was that they were server directories. I made the corrections that worked.
Dim Filename = "No_Image_Available.png"
Dim savePathcopy As String = Server.MapPath("~/IMAGES/")
Dim pathToCheckCopy As String = savePathcopy + Filename
'Dim mainSavePath As String = System.IO.Path.Combine(saveDirectory, Filename)
If (System.IO.File.Exists(pathToCheckCopy)) Then
' If System.IO.File.Exists(noImg) = True Then
Else
'file doesn't exist
My.Computer.FileSystem.CopyFile("\\..\Dev\web\WebUsers\...\..\Classified_Ads_V2\No_Image_Available.png", "\\...\Dev\web\WebUsers\...\..\...\IMAGES\No_Image_Available.png")
End If