With below code, I'm trying to extract a line from syslog file having string original value but I'm getting whole file data as output.
Sub test()
Dim InputData
' Open file for input.
Open "D:\temp\DraftTest3_pmi_jt_import_All_Annotations.syslog" For Input As #1
Do While Not EOF(1) ' Check for end of file.
Line Input #1, InputData ' Read line of data.
Debug.Print InputData ' Print to the Immediate window.
If InStr(1, InputData, "original value") Then
Cells(2, 3).Value = InputData ''' Print a line in cell
InputData = ""
End If
Loop
Close #1 ' Close file.
End Sub
Syslog content:
Nodes differ : original value 189.1596739640256
new value 191.1200796864099
Difference:
<object type="NXOpen.ValidationAnnotation3DCollectionValidator" value="None" xml_line_number="14" />
<context line_number="132" variable_name="validationAnnotation3DCollectionValidator1" xml_line_number="15" />
<object type="NXOpen.ValidationWeldValidator" value="None" xml_line_number="2675" />
<context line_number="0" variable_name="" xml_line_number="2676" />
<output name="WeldReferenceLineLength" xml_line_number="2677" />
<object tolerance="1e-06" tolerance_type="absolute" type="double" value="189.1596739640256" />
*** changed to ***
<object tolerance="1e-06" tolerance_type="absolute" type="double" value="191.1200796864099" xml_line_number="2678" />
_________________________________________________________________________________________
Nodes differ : original value 102.5546050485778
new value 102.8898888970786
Difference:
<object type="NXOpen.ValidationAnnotation3DCollectionValidator" value="None" xml_line_number="14" />
<context line_number="132" variable_name="validationAnnotation3DCollectionValidator1" xml_line_number="15" />
<object type="NXOpen.ValidationWeldValidator" value="None" xml_line_number="4422" />
<context line_number="0" variable_name="" xml_line_number="4423" />
<output name="WeldReferenceLineLength" xml_line_number="4424" />
<object tolerance="1e-06" tolerance_type="absolute" type="double" value="102.5546050485778" />
Desired output:
Do you want to extract the value 189.1596739640256? – Siddharth Rout 7 mins ago
Yes. I want that value. – Experimenter 6 mins ago
The fastest way to get that value would be
Open and read the text file in ONE GO. i.e without looping
Split on original value
And then split on new value
Code:
Option Explicit
Sub Sample()
Dim MyData As String, ValueNeeded As String
'~~> Change this to the relevant file
'~~> Read the entire file in a variable in ONE GO
Open "C:\Users\routs\Desktop\Sample.Txt" For Binary As #1
MyData = Space$(LOF(1))
Get #1, , MyData
Close #1
ValueNeeded = Trim(Split(MyData, "original value")(1))
ValueNeeded = Trim(Split(ValueNeeded, "new value")(0))
Debug.Print ValueNeeded
End Sub
Screenshot
EDIT
To incorporate multiple instances as shown in your recent edit, you will have to look for a unique word. In your case it would be Nodes differ :. Why this? becuase this signifies a new section. So the logic would be to split on Nodes differ : and then split on original value, new value and Difference:
See this example
Option Explicit
Sub Sample()
Dim MyData As String, ValueString As String
Dim orgVal As String, newVal As String
Dim strData() As String
Dim i As Long
'~~> Change this to the relevant file
'~~> Read the entire file in a variable in ONE GO
Open "C:\Users\routs\Desktop\test.Txt" For Binary As #1
MyData = Space$(LOF(1))
Get #1, , MyData
Close #1
'~~> Split on "Nodes differ :" to identify separate sections
'~~> Store them in an array
strData() = Split(MyData, "Nodes differ :")
'~~> Loop though each section and split on relevant identifiers
'~~> to get the necessary value
For i = LBound(strData) + 1 To UBound(strData)
ValueString = Trim(Split(strData(i), "original value")(1))
orgVal = Trim(Split(ValueString, "new value")(0))
newVal = Trim(Split(ValueString, "new value")(1))
newVal = Trim(Split(newVal, "Difference:")(0))
Debug.Print "Original Value: " & Trim(orgVal)
Debug.Print "New Value: " & Trim(newVal)
Next i
End Sub
NOTE: I have not done any error handling. I am sure you will take care of that...
InStr returns a Variant, not a Boolean. Try changing your comparison to If InStr(...) > 0. Docs are at https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/instr-function .
I also note that you are overwriting a single cell with each value in turn. If you want to save all the values, you will need to change how you index Cells.
Edit Line Input cannot handle Unix-type text files (LF-only line endings). See, e.g., https://chandoo.org/forum/threads/line-input-reads-entire-text-file-as-a-single-record.23089/ . Try the answers at Loading linux text file into excel using VBA . In short, you have to read the whole file (which you already do :) ) and then split it on vbLf to get individual lines.
Related
I'm trying to copy the values from multiple cells into one cell. If I only wanted to have the values of the cells combined, I would use something like
Dim str as string = My.Computer.ClipBoard.GetText
oxlapp.ActiveCell.Value = str
However
In this case I need to include html tagging, to create a table and I also want to include formatting like bold, italic and underlined. Therefore, instead of just the text from the clipboard, I need to know some cell properties.
I know that they should be there, because you can copy/paste entire cells of course.
So far I tried getting the Excel cells by using
My.Computer.Clipboard.GetData(XlClipboardFormat.xlClipboardFormatTable)
and
My.Computer.Clipboard.GetData(XlClipboardFormat.xlClipboardFormatCSV)
but while debugging I noticed that both of them returned Nothing.
Does someone know how I can get all cell properties from the clipboard?
To make it more clear, I want this
To turn into this:
If there is any other way than using the clipboard, I would be happy to try.
You need to use another format from clipboard - XML Spreadsheet. The copied data is contained in special XML with its own structure and attributes. Let's take the following sheet's data:
As you see, every cell has some formatting. The XML for this data is the following:
<ss:Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<ss:Styles>
<ss:Style ss:ID="Default" ss:Name="Normal">
<ss:Alignment ss:Vertical="Bottom"/>
<ss:Borders/>
<ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#000000"/>
<ss:Interior/>
<ss:NumberFormat/>
<ss:Protection/>
</ss:Style>
<ss:Style ss:ID="s62">
<ss:Interior ss:Color="#FFFF00" ss:Pattern="Solid"/>
</ss:Style>
<ss:Style ss:ID="s63">
<ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#000000" ss:Bold="1"/>
</ss:Style>
<ss:Style ss:ID="s64">
<ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#0000FF"/>
</ss:Style>
<ss:Style ss:ID="s65">
<ss:Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11" ss:Color="#000000" ss:Italic="1"/>
</ss:Style>
</ss:Styles>
<ss:Worksheet ss:Name="Sheet1">
<ss:Table ss:ExpandedColumnCount="2" ss:ExpandedRowCount="2" ss:DefaultRowHeight="15">
<ss:Row>
<ss:Cell ss:StyleID="s62">
<ss:Data ss:Type="String">A</ss:Data>
</ss:Cell>
<ss:Cell ss:StyleID="s63">
<ss:Data ss:Type="String">1</ss:Data>
</ss:Cell>
</ss:Row>
<ss:Row>
<ss:Cell ss:StyleID="s64">
<ss:Data ss:Type="String">B</ss:Data>
</ss:Cell>
<ss:Cell ss:StyleID="s65">
<ss:Data ss:Type="String">2</ss:Data>
</ss:Cell>
</ss:Row>
</ss:Table>
</ss:Worksheet>
</ss:Workbook>
As you see, you have all information about formatting in corresponding styles. For instace, value A in A1 cell has style s62 (StyleID attribute) - you can find the appropriate Style node with this number in Styles node. The structure of rows and columns in this XML is implicit - i.e. you won't see indexes of rows and columns - you need to calculate them yourself. For instance, the second Cell node in first Row node is first row, second column.
The following code generates data in the picture above and retrieves appropriate elements to manipulate.
A word of caution 1. If you take a look closely, the Workbook node has two urn:schemas-microsoft-com:office:spreadsheet namespaces: first is default and second is with prefix ss. Just remember - you always need to use ss prefix!
A word of caution 2. This method has one drawback - it doesn't understand hidden rows (manually or by autofilter) and columns! It includes hidden rows/columns, too!
Imports <xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
Imports <xmlns:x="urn:schemas-microsoft-com:office:excel">
Sub GetCellsWithFormat()
'// Create new Excel app
Dim xlApp = New Excel.Application With {.Visible = True}
Dim book = xlApp.Workbooks.Add()
Dim sheet = DirectCast(book.Sheets(1), Excel.Worksheet)
'// Apply some formatting
With sheet
.Range("A1").Interior.Color = Excel.XlRgbColor.rgbYellow
.Range("B1").Font.Bold = True
.Range("A2").Font.Color = Excel.XlRgbColor.rgbBlue
.Range("B2").Font.Italic = True
'// Add some values
Dim arr = Array.CreateInstance(GetType(String), {2, 2}, {1, 1})
arr(1, 1) = "A" : arr(1, 2) = "1"
arr(2, 1) = "B" : arr(2, 2) = "2"
With .Range("A1:B2")
.Value = arr
.Copy() '//Copy cells to clipboard
End With
Dim xml As XElement
Using xml_stream = DirectCast(Clipboard.GetData("XML Spreadsheet"), Stream)
'// Get rid of last character (new line) to avoid parsing error
xml_stream.SetLength(xml_stream.Length - 1)
xml = XElement.Load(xml_stream)
End Using
'// Get any element you need
Dim styles = xml.<ss:Styles>(0)
Dim table = xml.<ss:Worksheet>.<ss:Table>(0)
Dim rows = table.<ss:Row>
'// Do something with this data
End With
End Sub
UPDATE
In fact, you don't need to use clipboard to get this XML - you just need to use xlRangeValueXMLSpreadsheet value of Value property:
With sheet
'// Same code...
With .Range("A1:B2")
.Value = arr
'.Copy() '//No need to copy!
End With
Dim xml_string = CStr(.Range("A1:B2").Value(Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet))
'// Again, exclude last character
Dim xml = XElement.Parse(xml_string.Substring(0, xml_string.Length - 1))
'// Get any element you need
Dim styles = xml.<ss:Styles>(0)
Dim table = xml.<ss:Worksheet>.<ss:Table>(0)
Dim rows = table.<ss:Row>
'// Do something with this data
End With
When I want to allow data copied from Excel into a custom windows app that I wrote, I use GetText() instead of GetData().
Dim ClipboardText As String = Nothing
ClipboardText = My.Computer.Clipboard.GetText()
If it is multiple cells that are copied to the Clipboard from Excel, they could be seperated by vbTab and vbCrLf depending on the selection.
I have a XML file that contain a lot of information.
So, I would like to create a macro in VBA Excel that allow me to filter the information based on the accountID (available form an Userform - ComboBox)
It's the first time I work with XML and userform.
I've tried to adjust multiple code that I found on the net, but i understand better this one so I would like to continue with something similar (if possible):
Private Sub ComboBox1_Click()
Dim wks As Worksheet
Set wks = Sheet2
' Load the XML document
Dim XDoc As Object, root As Object
Set XDoc = CreateObject("MSXML2.DOMDocument")
XDoc.async = False: XDoc.validateOnParse = False
XDoc.Load ("C:\Users\isabelle\Google Drive\IB API Integration\Flexqueries\FlexDay.xml")
Dim singleNode As Object
Set singleNode = XDoc.SelectSingleNode("//FlexQueryResponse/FlexStatements/FlexStatement[#accountId='U2396623']")
End Sub
The accountId 'U2396623' is only an example. This will correspond to the entry in the combobox.
My two problems are :
First, I don't know how to link the entry in the combobox to the code (based on the accountID)
Second, code above does not work. I think the path (XDoc.SelectSingleNode) is not the right one... So, I tied several combination and it never worked. Or maybe it's the output that does not work correctly (The output should be in the Sheet2 )
My XML file looks like it :
<FlexQueryResponse queryName="Sample_1" type="AF">
<FlexStatements count="10">
<FlexStatement accountId="" fromDate="2019-04-22" toDate="2019-05-21" period="Last30CalendarDays" whenGenerated="2019-05-22;13:49:30">
<AccountInformation accountId="" acctAlias="" currency="CAD" accountType="Advisor Client" dateOpened="2018-02-08" dateFunded="2018-03-01" dateClosed="" street="" street2="" city="" state="" country="" postalCode="" primaryEmail="" />
<ChangeInNAV accountId="" acctAlias="" startingValue="" endingValue="" realized="0" changeInUnrealized="0" depositsWithdrawals="0" twr="" mtm="" dividends="" changeInDividendAccruals="" interest="" changeInInterestAccruals="" advisorFees="" clientFees="0" otherFees="0" />
<CashReport>
<CashReportCurrency accountId="" acctAlias="" clientFees="0" commissions="" deposits="0" withdrawals="0" accountTransfers="0" dividends="" advisorFees="" otherFees="0" currency="BASE_SUMMARY" startingCash="" endingCash="" endingSettledCash="" />
/>
</CashReport>
<OpenPositions>
<OpenPosition accountId="" acctAlias="" symbol="" position="" costBasisPrice="" strike="" expiry="" putCall="" positionValue="" percentOfNAV="" fifoPnlUnrealized="" currency="CAD" fxRateToBase="1" assetCategory="STK" description="BOMBARDIER INC PFD SER 2" securityID="CA0977515075" cusip="" isin="CA0977515075" />
</OpenPositions>
<FxPositions>
<FxPosition accountId="" fxCurrency="CAD" quantity="" costPrice="" unrealizedPL="0" />
</FxPositions>
<OptionEAE>
<OptionEAE accountId="" acctAlias="" currency="USD" assetCategory="" symbol="" description="" securityID="" cusip="" isin="" listingExchange="" underlyingConid="" underlyingSymbol="FCAU" underlyingSecurityID="NL0010877643" underlyingListingExchange="NYSE" issuer="" strike="16" expiry="2019-05-03" putCall="C" date="2019-04-22" transactionType="Assignment" quantity="2" tradePrice="0.0000" markPrice="0.3500" realizedPnl="0.00" />
</OptionEAE>
<PendingExcercises />
<ClientFees />
<OpenDividendAccruals>
<OpenDividendAccrual accountId="" acctAlias="" currency="" assetCategory="" symbol="" description="" securityID="" cusip="" isin="" exDate="2019-05-03" payDate="2019-06-24" quantity="400" grossRate="0.23" grossAmount="92" netAmount="92" />
</OpenDividendAccruals>
</FlexStatement>
</FlexStatements>
</FlexQueryResponse>
If you have any question don't hesitate !
Thank you for your help
Consider several adjustments:
Use the AfterUpdate trigger event of combobox.
Private Sub ComboBox1_AfterUpdate()
...
End Sub
Simply concatenate the combobox value Me.ComboBox1 to XPath expression.
XDoc.SelectSingleNode("/FlexQueryResponse/FlexStatements/FlexStatement[#accountId='" & Me.ComboBox1 & "']")
Select the needed attribute value or loop through multiple by node for extraction to sheet.
Private Sub ComboBox1_AfterUpdate()
' Load the XML document
Dim XDoc As Object, root As Object, singleNode As Object
Dim i As Integer
Set XDoc = CreateObject("MSXML2.DOMDocument")
XDoc.async = False: XDoc.validateOnParse = False
XDoc.Load ("C:\Users\isabelle\Google Drive\IB API Integration\Flexqueries\FlexDay.xml")
' OUTPUT ONE ATTRIBUTE OF NODE
Set singleNode = XDoc.SelectSingleNode("/FlexQueryResponse/FlexStatements/FlexStatement[#accountId='" & Me.ComboBox1 & "']")
ThisWorkbook.Worksheets("Sheet1").Range("A1") = singleNode.Attributes.getNamedItem("accountId").Text
' OUTPUT ALL ATTRIBUTES OF NODE
For i = 0 To singleNode.Attributes.Length - 1
ThisWorkbook.Worksheets("Sheet1").Range("A" & i + 1) = singleNode.Attributes(i).Name
ThisWorkbook.Worksheets("Sheet1").Range("B" & i + 1) = singleNode.Attributes(i).Text
Next i
Set XDoc = Nothing
End Sub
I need to save information from a text file into an array. But I dont know what the specific syntax is.
The information from the text file is about 2000 lines, which obviously you cant store within the vba script. The text looks like the below in one
35SLFR0006350
35SLFR0026350
35SLFR0106350
BARSQR1306000
C280BD1016000
C280BD1016000_mitre
C280BD1016000_square
C280FR0006000
C280MU0006000
C280MU0026000
C280SH0006000
C280SH0006000_outer frame
C305BD0006000
C305BD0006000_mitre
C305BD0006000_square
C305BD0016000
C305BD0016000_mitre
C305BD0016000_square
C305BD2006000
C305BD2006000_mitre
C305BD2006000_square
C305FR0006000
C305MU0006000
C305MU0026000
C305MU0046000
C305SH0006000
C305SH0006000_Un E frame
C340BD1006000_mitre
C340BD1006000_Right,Left,Horizontal
C340BD1006000_Right,Left,Vertical
C340BD1006000_square
C340FR00060000
C340MU0006000
C340MU0026000
C340SH0006000
If you want to save your input file as an array you can first read the whole file and save it as one whole string.
You can then use the Split function with the delimiter \n to return an array, where every element corresponds to one line of the file.
Const file As String = "<pathToFile>"
Dim ResultArray() As String
Dim tempString As String
Dim fn As Integer
fn = FreeFile()
Open file For Input As fn
While Not EOF(fn)
Line Input #fn, LineString
tempString = tempString & LineString & "\n"
Wend
ResultArray = Split(tempString, "\n")
Exported text files from Excel are encoded with UTF-8.
An encoding UTF-8-BOM is needed.
I think that in code shall be inserted a row, written like:
Java
?xml version="1.0" encoding="UTF-8"?
Jasperreport CSV UTF-8 without BOM instead of UTF-8
or
HTML5
meta charset="utf-8"
Bad UTF-8 without BOM encoding
Sub export_data()
Dim row, column, i, j As Integer
Dim fullPath, myFile As String
fullPath = "C:\Workspace"
row = 21
column = 5
For i = 1 To column
myFile = Cells(1, i).Value + ".txt"
myFile = fullPath + "/" + myFile
Open myFile For Output As #1
For j = 2 To row
Print #1, Cells(j, i).Value
Next j
Close #1
Next i
End Sub
How can I define and where to put a row, which defines encoding UTF-8-BOM?
Thank You.
Instead of Printing the file line by line, it might be more efficient to
save your selected range as a CSV UTF-8
you might need to change the file type after saving
Use ADO to process the file as UTF-8
Either will add a BOM automatically.
EDIT
If you are unfamiliar, you could perform the save to csv - utf8 process manually with the macro recorder turned on. Then examine what you have recorded and make appropriate edits.
Another way of adding the BOM, in the context of your existing code, would be to write it directly as a byte array to the first line.
For example:
Dim BOM(0 To 2) As Byte 'EF BB BF
BOM(0) = &HEF
BOM(1) = &HBB
BOM(2) = &HBF
Open myFile For Binary Access Write As #1
Put #1, 1, BOM
Close #1
will put the BOM at the beginning of the file.
You should then change the mode in your subsequent Print code to Append.
I suggest you read about the pros and cons of using Print vs Write
You should also read about declaration statements. In yours, only the last variable on each line is being declared as the specified type; the preceding variables are being implicitly declared as being of type Variant.
I have this kind of CSV :
So when I import in EXCEL 2013 with "get data from text file",
1) how to say separator IS QUOTES + COMMA,
2) For Excel, BREAK LINE in fields are new line of data... how to say it's not ?
I know that CSV are a long topic on the Web, but there is no obvious solution.
So thanks for your help.
Step 1: I would first fix the file:
Sub ImportData()
Dim dataTextFile As String
Dim outTextFile As String, splitPart As String, missingPart As String, ret As String
'---Read the file---
Open "C:\Data.txt" For Input As #1
dataTextFile = Input$(LOF(1), 1)
Close #1
dataTextFile = Replace(dataTextFile, vbNewLine, "[NEW_LINE]")
ret = GetRegex("(.*?,.*?,.*?),")
outTextFile = outTextFile & ret & vbNewLine
Do While 1
If (ret = GetRegex(dataTextFile, ",(.*?,.*?,.*?)")) <> "" Then
Exit Do
Else
outTextFile = outTextFile & ret & vbNewLine
dataTextFile = Right(dataTextFile, Len(dataTextFile) - Len(ret))
End If
Loop
'---Write back to the file---
Open "C:\Data.txt" For Output As #1
Write #1, outTextFile
Close #1
End Sub
You can find the GetRegex function here: link. Or just use the general Regex object. Warning: I haven't tested the code so you might need to do some tinkering.
Step 2: Next you simply import the file normally via the Import Wizard as comma separated file.
Step 3: Lastly replace "[NEW_LINE]" with New Line characters via macro or whatever other way.
Alternatively you may just as well do steps 2-3 in the same macro - and use the Right function or a Regex to extract the column to your output worksheet.