Parsing CSV string and binding it to listbox - vb.net

I have splitted comma separated values in an string array, something like this
str[0] ="210"
str[1] ="abc.pdf"
str[2] = "211"
str[3] = "xyz.docx"
and so on. Please note 0,2,4,6,8 [even positions] are having number and odd positions are having string.
I am having a class Attachmodel
Public Class AttachmentModel
Private _attachmentID As Integer = 0
Private _attachmentPath As String = ""
''' <summary>
''' Get Set Attachment ID
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property AttachmentID() As Integer
Get
Return _attachmentID
End Get
Set(ByVal value As Integer)
_attachmentID = value
End Set
End Property
''' <summary>
''' Get Set Attachment Path
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property AttachmentPath() As String
Get
Return _attachmentPath
End Get
Set(ByVal value As String)
_attachmentPath = value
End Set
End Property
End Class
In the above i want to set the values and bind it to the grid, using List

I want to bind CSV string with listbox programmatically
Private Sub BindAttachmentsToListBox(ByVal collectionData As String)
Dim arrayString As String()
Dim separator As String() = {",", "\n", " "}
Dim attachmentList As New List(Of AttachmentModel)
arrayString = collectionData.ToString().Split(separator, StringSplitOptions.RemoveEmptyEntries)
For i As Integer = 0 To arrayString.Length - 1
Dim attachments As New AttachmentModel()
attachments.AttachmentID = Integer.Parse(arrayString(i).ToString().Trim())
attachments.AttachmentPath = arrayString(i + 1).ToString.Trim()
attachmentList.Add(attachments)
i = i + 1
Next
lbAttachments.DataSource = attachmentList
lbAttachments.DisplayMember = "AttachmentPath"
lbAttachments.ValueMember = "AttachmentID"
End Sub

Related

Load Torrent in VB.NET with Monotorrent

im making a simply app to download torrent files, using MonoTorrent. But i cant load the torrent properly, and I've looked all available information.
That's the code im using:
Imports MonoTorrent.BEncoding
Imports MonoTorrent.Client
Imports MonoTorrent.Client.Tracker
Imports MonoTorrent.Common
Imports System.IO
Imports System.Net
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
End Class
Module BitTorrentAnnounceReader
Sub main()
'load Torrentfile
Dim TorrentFile As torrent = ("D:\youtorrent.torrent")
Console.WriteLine(TorrentFile.Name)
'generate annouce paramters
'since we simluate a BitTornado Client double check PeerID and Key Paramter
Dim AnnounceParameter As New AnnounceParameters
AnnounceParameter.BytesLeft = TorrentFile.Size
AnnounceParameter.BytesUploaded = 0
AnnounceParameter.BytesDownloaded = 0
AnnounceParameter.Port = 12224
AnnounceParameter.InfoHash = TorrentFile.InfoHash
AnnounceParameter.PeerId = "T03I-----" & GenerateTorrentClientKeys(11, 1)
AnnounceParameter.ClientEvent = TorrentEvent.Started
'a torrentfile can have more than one url, we use only the first one
'the url should have http to work for this example
Dim AnnounceUrl As String = TorrentFile.AnnounceUrls.Item(0).Item(0).ToString
Console.WriteLine(AnnounceUrl)
'the full announceurl that will fired to tracker
'we are simulating a BitTorando Client
Dim FullAnnounceUrl As String = CreateAnnounceString(AnnounceParameter, AnnounceUrl, GenerateTorrentClientKeys(6))
'building a webrequest for tracker request; some silly line look at comments on
'MonoTorrent.Client.Tracker.HTTPTracker.Announce
Dim req As HttpWebRequest = CType(WebRequest.Create(FullAnnounceUrl), HttpWebRequest)
req.KeepAlive = False
req.Proxy = New WebProxy
'we want to simulate a BitTornado Client, so http headers
req.UserAgent = "User-Agent: BitTornado/T-0.3.18"
'to simulate full client we need also gzip but for better usage we dont use it
' req.Headers.Add("Accept-Encoding", "gzip")
' If (resp.ContentEncoding.ToLower().Contains("gzip")) Then
' Str = New IO.Compression.GZipStream(Str, IO.Compression.CompressionMode.Decompress)
Dim response As HttpWebResponse = req.GetResponse
Dim fs As Stream = WebResponseToStream(response)
Dim peers As List(Of Peer) = AnnounceGetPeerList(fs)
Console.WriteLine("Tracker returned:" & peers.Count)
For Each PeerInfo As Peer In peers
Console.WriteLine(PeerInfo.ConnectionUri.Host & ":" & PeerInfo.ConnectionUri.Port)
Next
Console.ReadKey()
End Sub
''' <summary>
''' Generate a random key depending on which TorrentClient to simulate
''' </summary>
''' <param name="len"></param>
''' <param name="keys"></param>
''' <returns></returns>
''' <remarks></remarks>
Function GenerateTorrentClientKeys(ByVal len As Integer, Optional ByVal keys As Integer = 1) As String
Dim Chars() As String = {"abcdefghijklmnopqrstuvwxyz0123456789", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"}
'Chars[0] = uTorrent Keys
'Chars[1] = BitTornado Keys
Dim str As String = ""
Dim r As New System.Random()
For i = 1 To len
str &= Chars(keys).Substring(r.Next(1, Chars(keys).Length), 1)
Next
Return str
End Function
''' <summary>
''' A simple way of parsing a bencoded peerlist. it will autodecode compact mode request
''' you can find the full announce parser in the orignal file:
'''
''' MonoTorrent.Client.Tracker.HTTPTracker.HandleAnnounce
''' http://anonsvn.mono-project.com/viewvc/trunk/bitsharp/src/MonoTorrent/MonoTorrent.Client/Tracker/HTTPTracker.cs
''' </summary>
''' <param name="fs"></param>
''' <returns></returns>
''' <remarks></remarks>
Function AnnounceGetPeerList(ByVal fs As Stream) As List(Of Peer)
'you can also use a file with a torrenrequest
'Dim reader As New RawReader(IO.File.Open("file.req", IO.FileMode.Open), False)
'decode the bencoded stream
Dim dictionary As BEncodedDictionary = BEncodedValue.Decode(Of BEncodedDictionary)(fs)
Dim peers As New List(Of Peer)
For Each keypair In dictionary
Select Case keypair.Key.ToString
Case "interval"
'MsgBox TimeSpan.FromSeconds(int.Parse(keypair.Value.ToString()));
'MsgBox(keypair.Value.ToString)
Case "peers"
If TypeOf keypair.Value Is BEncodedList Then
peers.AddRange(Peer.Decode(DirectCast(keypair.Value, BEncodedList)))
ElseIf TypeOf keypair.Value Is BEncodedString Then
peers.AddRange(Peer.Decode(DirectCast(keypair.Value, BEncodedString)))
End If
Case Else
'MsgBox("HttpTracker - Unknown announce tag received:" & keypair.Key.ToString() & keypair.Value.ToString())
End Select
Next
Return peers
End Function
''' <summary>
''' Original CreateAnnounceString is private only and we need to modify it a little bit; this the old one out of svn
''' they have created here a better function that uses UriQueryBuilder but its oversized here
'''
''' MonoTorrent.Client.Tracker.HTTPTracker.CreateAnnounceString
''' http://anonsvn.mono-project.com/viewvc/trunk/bitsharp/src/MonoTorrent/MonoTorrent.Client/Tracker/HTTPTracker.cs?revision=141866
''' </summary>
''' <param name="parameters"></param>
''' <param name="Uri">AnnounceURL of the TorrentFile</param>
''' <param name="Key">a radon key paramter</param>
''' <returns>url to use with a WebRequest</returns>
''' <remarks></remarks>
Private Function CreateAnnounceString(ByVal parameters As AnnounceParameters, ByVal Uri As String, ByVal Key As String) As String
Dim sb As New System.Text.StringBuilder(256)
'base.LastUpdated = DateTime.Now;
' FIXME: This method should be tidied up. I don't like the way it current works
sb.Append(Uri)
sb.Append(If(Uri.Contains("?"), "&"c, "?"c))
sb.Append("info_hash=")
sb.Append(parameters.InfoHash.UrlEncode())
sb.Append("&peer_id=")
sb.Append(parameters.PeerId)
sb.Append("&port=")
sb.Append(parameters.Port)
If parameters.SupportsEncryption Then
sb.Append("&supportcrypto=1")
End If
If parameters.RequireEncryption Then
sb.Append("&requirecrypto=1")
End If
sb.Append("&uploaded=")
sb.Append(parameters.BytesUploaded)
sb.Append("&downloaded=")
sb.Append(parameters.BytesDownloaded)
sb.Append("&left=")
sb.Append(parameters.BytesLeft)
sb.Append("&compact=1")
' Always use compact response
sb.Append("&numwant=")
sb.Append(100)
If Not Uri.Contains("&key=") AndAlso Not Uri.Contains("?key=") Then
sb.Append("&key=")
' The 'key' protocol, used as a kind of 'password'. Must be the same between announces
sb.Append(Key)
End If
If parameters.Ipaddress IsNot Nothing Then
sb.Append("&ip=")
sb.Append(parameters.Ipaddress)
End If
' If we have not successfully sent the started event to this tier, override the passed in started event
' Otherwise append the event if it is not "none"
'if (!parameters.Id.Tracker.Tier.SentStartedEvent)
'{
' sb.Append("&event=started");
' parameters.Id.Tracker.Tier.SendingStartedEvent = true;
'}
If parameters.ClientEvent <> TorrentEvent.None Then
sb.Append("&event=")
sb.Append(parameters.ClientEvent.ToString().ToLower())
End If
Return sb.ToString()
End Function
''' <summary>
''' HttpWebResponse and GetResponseStream dont gives use a full readable stream so we must convert it
'''
''' Look at: MonoTorrent.Client.Tracker.HTTPTracker.DecodeResponse
''' http://anonsvn.mono-project.com/viewvc/trunk/bitsharp/src/MonoTorrent/MonoTorrent.Client/Tracker/HTTPTracker.cs
''' or
''' http://bytes.com/topic/c-sharp/answers/232436-download-binary-file-http#post949811
''' </summary>
''' <param name="response"></param>
''' <returns></returns>
''' <remarks></remarks>
Function WebResponseToStream(ByVal response As HttpWebResponse) As Stream
Dim responseStream As Stream = response.GetResponseStream
Dim fs As MemoryStream = New MemoryStream(256)
Dim buffer As Byte() = New Byte(4095) {}
Dim length As Integer = responseStream.Read(buffer, 0, 4096)
While length > 0
fs.Write(buffer, 0, length)
length = responseStream.Read(buffer, 0, 4096)
End While
fs.Seek(0, SeekOrigin.Begin)
Return fs
End Function
End Module
The problem only appears in the load file .torrent part:
Dim TorrentFile As **torrent** = ("D:\youtorrent.torrent")
Vb.net throws me an error of "Type expected 'on the text torrent. there any solution? Thanks to all!
Try
Dim TorrentFile As torrent = Torrent.Load("D:\youtorrent.torrent")

HTTP Post a file and params to PHP page using VB.net

I found this code in order to do a PHP Post in VB.NET with params, however I don't really understand how to also send a file with it as well?
My PHP page watches for $_POST["file"] and I just need to be able to send foo=bar & foo2=bar to my PHP page, and also upload "file" as well.
Here is the method I been using so far and seems to be working OK with posting the foo and foo2
Public Function PHP(ByVal url As String, ByVal method As String, ByVal data As String)
Try
Dim request As System.Net.WebRequest = System.Net.WebRequest.Create(url)
request.Method = method
Dim postData = data
Dim byteArray As Byte() = System.Text.Encoding.UTF8.GetBytes(postData)
request.ContentType = "application/x-www-form-urlencoded"
request.ContentLength = byteArray.Length
Dim dataStream As Stream = request.GetRequestStream()
dataStream.Write(byteArray, 0, byteArray.Length)
dataStream.Close()
Dim response As WebResponse = request.GetResponse()
dataStream = response.GetResponseStream()
Dim reader As New StreamReader(dataStream)
Dim responseFromServer As String = reader.ReadToEnd()
reader.Close()
dataStream.Close()
response.Close()
Return (responseFromServer)
Catch ex As Exception
Dim error1 As String = ErrorToString()
If error1 = "Invalid URI: The format of the URI could not be determined." Then
MsgBox("ERROR! Must have HTTP:// before the URL.")
Else
MsgBox(error1)
End If
Return ("ERROR")
End Try
End Function
I found an awesome class a guy named Greg wrote originally in C# that I had gotten converted to VB.NET and it works beautifully. It was found on: http://www.c-sharpcorner.com/UploadFile/gregoryprentice/DotNetBugs12062005230632PM/DotNetBugs.aspx
To use code below..
Dim form As New MultipartForm(URL)
form.setField("param1", "foo")
form.setField("param2", "bar")
form.sendFile("C:\test.PDF")
Dim Response as String = form.ResponseText.ToString
Below is the actual in case the URL ever breaks because its such a great piece of code which is now in VB.NET
Imports System.Net
Imports System.Text
Imports System.IO
Imports System.Collections
Namespace norvanco.http
''' <summary>
''' Allow the transfer of data files using the W3C's specification
''' for HTTP multipart form data. Microsoft's version has a bug
''' where it does not format the ending boundary correctly.
''' Written by: gregoryp#norvanco.com
''' </summary>
Public Class MultipartForm
''' <summary>
''' Holds any form fields and values that you
''' wish to transfer with your data.
''' </summary>
Private coFormFields As Hashtable
''' <summary>
''' Used mainly to avoid passing parameters to other routines.
''' Could have been local to sendFile().
''' </summary>
Protected coRequest As HttpWebRequest
''' <summary>
''' Used if we are testing and want to output the raw
''' request, minus http headers, out to a file.
''' </summary>
Private coFileStream As System.IO.Stream
''' <summary>
''' Difined to build the form field data that is being
''' passed along with the request.
''' </summary>
Shared CONTENT_DISP As String = "Content-Disposition: form-data; name="
''' <summary>
''' Allows you to specify the specific version of HTTP to use for uploads.
''' The dot NET stuff currently does not allow you to remove the continue-100 header
''' from 1.1 and 1.0 currently has a bug in it where it adds the continue-100. MS
''' has sent a patch to remove the continue-100 in HTTP 1.0.
''' </summary>
Public Property TransferHttpVersion() As Version
Get
Return coHttpVersion
End Get
Set(ByVal value As Version)
coHttpVersion = value
End Set
End Property
Private coHttpVersion As Version
''' <summary>
''' Used to change the content type of the file being sent.
''' Currently defaults to: text/xml. Other options are
''' text/plain or binary
''' </summary>
Public Property FileContentType() As String
Get
Return coFileContentType
End Get
Set(ByVal value As String)
coFileContentType = value
End Set
End Property
Private coFileContentType As String
''' <summary>
''' Initialize our class for use to send data files.
''' </summary>
''' <param name="url">The web address of the recipient of the data transfer.</param>
Public Sub New(ByVal url__1 As String)
URL = url__1
coFormFields = New Hashtable()
ResponseText = New StringBuilder()
BufferSize = 1024 * 10
BeginBoundary = "ou812--------------8c405ee4e38917c"
TransferHttpVersion = HttpVersion.Version11
FileContentType = "text/xml"
End Sub
'---------- BEGIN PROPERTIES SECTION ----------
Private _BeginBoundary As String
''' <summary>
''' The string that defines the begining boundary of
''' our multipart transfer as defined in the w3c specs.
''' This method also sets the Content and Ending
''' boundaries as defined by the w3c specs.
''' </summary>
Public Property BeginBoundary() As String
Get
Return _BeginBoundary
End Get
Set(ByVal value As String)
_BeginBoundary = value
ContentBoundary = Convert.ToString("--") & BeginBoundary
EndingBoundary = ContentBoundary & Convert.ToString("--")
End Set
End Property
''' <summary>
''' The string that defines the content boundary of
''' our multipart transfer as defined in the w3c specs.
''' </summary>
Protected Property ContentBoundary() As String
Get
Return _ContentBoundary
End Get
Set(ByVal value As String)
_ContentBoundary = value
End Set
End Property
Private _ContentBoundary As String
''' <summary>
''' The string that defines the ending boundary of
''' our multipart transfer as defined in the w3c specs.
''' </summary>
Protected Property EndingBoundary() As String
Get
Return _EndingBoundary
End Get
Set(ByVal value As String)
_EndingBoundary = value
End Set
End Property
Private _EndingBoundary As String
''' <summary>
''' The data returned to us after the transfer is completed.
''' </summary>
Public Property ResponseText() As StringBuilder
Get
Return _ResponseText
End Get
Set(ByVal value As StringBuilder)
_ResponseText = value
End Set
End Property
Private _ResponseText As StringBuilder
''' <summary>
''' The web address of the recipient of the transfer.
''' </summary>
Public Property URL() As String
Get
Return _URL
End Get
Set(ByVal value As String)
_URL = value
End Set
End Property
Private _URL As String
''' <summary>
''' Allows us to determine the size of the buffer used
''' to send a piece of the file at a time out the IO
''' stream. Defaults to 1024 * 10.
''' </summary>
Public Property BufferSize() As Integer
Get
Return _BufferSize
End Get
Set(ByVal value As Integer)
_BufferSize = value
End Set
End Property
Private _BufferSize As Integer
'---------- END PROPERTIES SECTION ----------
''' <summary>
''' Used to signal we want the output to go to a
''' text file verses being transfered to a URL.
''' </summary>
''' <param name="path"></param>
Public Sub setFilename(ByVal path As String)
coFileStream = New System.IO.FileStream(path, FileMode.Create, FileAccess.Write)
End Sub
''' <summary>
''' Allows you to add some additional field data to be
''' sent along with the transfer. This is usually used
''' for things like userid and password to validate the
''' transfer.
''' </summary>
''' <param name="key">The form field name</param>
''' <param name="str">The form field value</param>
Public Sub setField(ByVal key As String, ByVal str As String)
coFormFields(key) = str
End Sub
''' <summary>
''' Determines if we have a file stream set, and returns either
''' the HttpWebRequest stream of the file.
''' </summary>
''' <returns></returns>
Public Overridable Function getStream() As System.IO.Stream
Dim io As System.IO.Stream
If coFileStream Is Nothing Then
io = coRequest.GetRequestStream()
Else
io = coFileStream
End If
Return io
End Function
''' <summary>
''' Here we actually make the request to the web server and
''' retrieve it's response into a text buffer.
''' </summary>
Public Overridable Sub getResponse()
If coFileStream Is Nothing Then
Dim io As System.IO.Stream
Dim oResponse As WebResponse
Try
oResponse = coRequest.GetResponse()
Catch web As WebException
oResponse = web.Response
End Try
If oResponse IsNot Nothing Then
io = oResponse.GetResponseStream()
Dim sr As New StreamReader(io)
Dim str As String
ResponseText.Length = 0
While (InlineAssignHelper(str, sr.ReadLine())) IsNot Nothing
ResponseText.Append(str)
End While
oResponse.Close()
Console.Write(ResponseText)
Else
Throw New Exception("MultipartForm: Error retrieving server response")
End If
End If
End Sub
''' <summary>
''' Transmits a file to the web server stated in the
''' URL property. You may call this several times and it
''' will use the values previously set for fields and URL.
''' </summary>
''' <param name="aFilename">The full path of file being transfered.</param>
Public Sub sendFile(ByVal aFilename As String)
' The live of this object is only good during
' this function. Used mainly to avoid passing
' around parameters to other functions.
coRequest = DirectCast(WebRequest.Create(URL), HttpWebRequest)
' Set use HTTP 1.0 or 1.1.
coRequest.ProtocolVersion = TransferHttpVersion
coRequest.Method = "POST"
coRequest.ContentType = Convert.ToString("multipart/form-data; boundary=") & BeginBoundary
coRequest.Headers.Add("Cache-Control", "no-cache")
coRequest.KeepAlive = True
Dim strFields As String = getFormfields()
Dim strFileHdr As String = getFileheader(aFilename)
Dim strFileTlr As String = getFiletrailer()
Dim info As New FileInfo(aFilename)
coRequest.ContentLength = strFields.Length + strFileHdr.Length + strFileTlr.Length + info.Length
Dim io As System.IO.Stream
io = getStream()
writeString(io, strFields)
writeString(io, strFileHdr)
Me.writeFile(io, aFilename)
writeString(io, strFileTlr)
getResponse()
io.Close()
' End the life time of this request object.
coRequest = Nothing
End Sub
''' <summary>
''' Mainly used to turn the string into a byte buffer and then
''' write it to our IO stream.
''' </summary>
''' <param name="io">The io stream for output.</param>
''' <param name="str">The data to write.</param>
Public Sub writeString(ByVal io As System.IO.Stream, ByVal str As String)
Dim PostData As Byte() = System.Text.Encoding.ASCII.GetBytes(str)
io.Write(PostData, 0, PostData.Length)
End Sub
''' <summary>
''' Builds the proper format of the multipart data that
''' contains the form fields and their respective values.
''' </summary>
''' <returns>The data to send in the multipart upload.</returns>
Public Function getFormfields() As String
Dim str As String = ""
Dim myEnumerator As IDictionaryEnumerator = coFormFields.GetEnumerator()
While myEnumerator.MoveNext()
str += (Convert.ToString(ContentBoundary & Convert.ToString(vbCr & vbLf)) & CONTENT_DISP) + """"c + myEnumerator.Key + """" & vbCr & vbLf & vbCr & vbLf + myEnumerator.Value + vbCr & vbLf
End While
Return str
End Function
''' <summary>
''' Returns the proper content information for the
''' file we are sending.
''' </summary>
''' <remarks>
''' Hits Patel reported a bug when used with ActiveFile.
''' Added semicolon after sendfile to resolve that issue.
''' Tested for compatibility with IIS 5.0 and Java.
''' </remarks>
''' <param name="aFilename"></param>
''' <returns></returns>
Public Function getFileheader(ByVal aFilename As String) As String
Return (Convert.ToString((Convert.ToString(ContentBoundary & Convert.ToString(vbCr & vbLf)) & CONTENT_DISP) + """file1""; filename=""" + Path.GetFileName(aFilename) + """" & vbCr & vbLf + "Content-type: ") & FileContentType) + vbCr & vbLf & vbCr & vbLf
End Function
''' <summary>
''' Creates the proper ending boundary for the multipart upload.
''' </summary>
''' <returns>The ending boundary.</returns>
Public Function getFiletrailer() As String
Return Convert.ToString(vbCr & vbLf) & EndingBoundary
End Function
''' <summary>
''' Reads in the file a chunck at a time then sends it to the
''' output stream.
''' </summary>
''' <param name="io">The io stream to write the file to.</param>
''' <param name="aFilename">The name of the file to transfer.</param>
Public Sub writeFile(ByVal io As System.IO.Stream, ByVal aFilename As String)
Dim readIn As New FileStream(aFilename, FileMode.Open, FileAccess.Read)
readIn.Seek(0, SeekOrigin.Begin)
' move to the start of the file
Dim fileData As Byte() = New Byte(BufferSize - 1) {}
Dim bytes As Integer
While (InlineAssignHelper(bytes, readIn.Read(fileData, 0, BufferSize))) > 0
' read the file data and send a chunk at a time
io.Write(fileData, 0, bytes)
End While
readIn.Close()
End Sub
Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
target = value
Return value
End Function
End Class
End Namespace

Check if a string has all of it's parenthesis closed

Is there a way to check if a string has all of it's parenthesis closed? So for example it would take as an argument a string like this:
dim ValidOne as string = "This is (good)"
dim ValidOne as string = "This (is (good))"
dim InvalidOne as string = "This is (bad))"
dim InvalidOne as string = "This is (bad"
dim InvalidOne as string = "This is bad)"
And return True or False depending on whether there is a valid number of closed parenthesis.
So it if the string had an open ( and it was not closed, or just a ) that was never opened, it would return false.
I think you can do something like +1 for each open ( and -1 for each ). The rule is that you must end with 0 at the end.
If you want a full versatile and customizable solution then here is my approach:
Output:
Snippet:
''' <summary>
''' Counts the closed and opened pair of chars inside a String.
''' </summary>
''' <param name="PairChars">The pair character.</param>
''' <param name="Input">The string where to count the pair characters.</param>
''' <returns>PairCharacter.</returns>
''' <exception cref="System.Exception">Index of 'PairChar' parameter is out of range.</exception>
Public Function CountPairOfChars(ByVal PairChars As KeyValuePair(Of Char, Char),
ByVal Input As String) As PairOfCharsInfo
If String.IsNullOrEmpty(Input) OrElse String.IsNullOrWhiteSpace(Input) Then
Throw New Exception("'Input' parameter cannot be an empty String.")
End If
Dim CharStack As New Stack(Of Integer)
Dim Result As New PairOfCharsInfo
With Result
.Input = Input
.Characters = New KeyValuePair(Of Char, Char)(PairChars.Key, PairChars.Value)
For i As Integer = 0 To Input.Length - 1
Select Case Input(i)
Case .Characters.Key
CharStack.Push(i)
.OpenedPairsIndex.Add(i)
.CountOpenedPairs += 1
Case .Characters.Value
Select Case CharStack.Count
Case Is = 0
.CountOpenedPairs += 1
.OpenedPairsIndex.Add(i)
Case Else
.CountClosedPairs += 1
.CountOpenedPairs -= 1
.ClosedPairsIndex.Add(Tuple.Create(Of Integer, Integer)(CharStack.Pop, i))
.OpenedPairsIndex.RemoveAt(.OpenedPairsIndex.Count - 1)
End Select '/ CharStack.Count
End Select '/ Input(i)
Next i
.StringHasClosedPairs = .CountClosedPairs <> 0
.StringHasOpenedPairs = .CountOpenedPairs <> 0
End With '/ Result
Return Result
End Function
''' <summary>
''' Stores info about closed and opened pairs of chars in a String.
''' </summary>
Public NotInheritable Class PairOfCharsInfo
''' <summary>
''' Indicates the input string.
''' </summary>
''' <value>The input string.</value>
Public Property Input As String = String.Empty
''' <summary>
''' Indicates the pair of characters.
''' </summary>
''' <value>The pair of characters.</value>
Public Property Characters As KeyValuePair(Of Char, Char) = Nothing
''' <summary>
''' Determines whether the input string contains closed pairs of character.
''' </summary>
''' <value>The closed pairs count.</value>
Public Property StringHasClosedPairs As Boolean = False
''' <summary>
''' Determines whether the input string contains opened pairs of character.
''' </summary>
''' <value>The closed pairs count.</value>
Public Property StringHasOpenedPairs As Boolean = False
''' <summary>
''' Indicates the total amount of closed pairs.
''' </summary>
''' <value>The closed pairs count.</value>
Public Property CountClosedPairs As Integer = 0
''' <summary>
''' Indicates the total amount of opened pairs.
''' </summary>
''' <value>The opened pairs count.</value>
Public Property CountOpenedPairs As Integer = 0
''' <summary>
''' Indicates the closed pairs index position in the string.
''' </summary>
''' <value>The closed pairs positions.</value>
Public Property ClosedPairsIndex As New List(Of Tuple(Of Integer, Integer))
''' <summary>
''' Indicates the opened pairs index position in the string.
''' </summary>
''' <value>The opened pairs positions.</value>
Public Property OpenedPairsIndex As New List(Of Integer)
End Class '/ PairOfCharsInfo
Example Usage:
( The same as I used for the output images above)
Private Sub Test() Handles MyBase.Shown
Dim Inputs As String() =
{
"(This) is (good)",
"This (is (good))",
"This is good",
"This is (bad))",
"This is (bad",
"This is bad)",
"This is bad)("
}
Dim PairChars As New KeyValuePair(Of Char, Char)("(", ")")
For Each s As String In Inputs
Dim Info As PairOfCharsInfo = Me.CountPairOfChars(PairChars, s)
Dim sb As New System.Text.StringBuilder
With sb
.AppendLine(String.Format("Input String: {0}", Info.Input))
.AppendLine(String.Format("Pair of Chars: {0}{1}", Info.Characters.Key, Info.Characters.Value))
.AppendLine()
.AppendLine(String.Format("String has closed pairs?: {0}", Info.StringHasClosedPairs))
.AppendLine(String.Format("String has opened pairs?: {0}", Info.StringHasOpenedPairs))
.AppendLine()
.AppendLine(String.Format("Closed Pairs Count: {0}", Info.CountClosedPairs))
.AppendLine(String.Format("Opened Pairs Count: {0}", Info.CountOpenedPairs))
.AppendLine()
.AppendLine("Closed Pairs Indexes:")
For Each Item As Tuple(Of Integer, Integer) In Info.ClosedPairsIndex
.AppendLine(String.Format("Start Index: {0}, End Index: {1}",
CStr(Item.Item1), CStr(Item.Item2)))
Next Item
.AppendLine()
.AppendLine(String.Format("Opened Pairs Indexes: {0}",
String.Join(", ", Info.OpenedPairsIndex)))
End With '/ sb
MessageBox.Show(sb.ToString, "Count Pair Characters Information",
MessageBoxButtons.OK, MessageBoxIcon.Information)
Next s
End Sub
Something like this should do it:
Public Shared Function TestStringParens(s As String) As Boolean
Dim Ret = 0
For Each C In s
If C = ")"c Then Ret -= 1
If C = "("c Then Ret += 1
'Bail earlier for a closed paren without a matching open
If Ret < 0 Then Return False
Next
Return Ret = 0
End Function
As your post and some other people have said just keep a counter around and walk the string. As #Drico said, any time a negative counter exists then we have a closed parentheses without a corresponding open.
You can test this with:
Dim Tests As New Dictionary(Of String, Boolean)
Tests.Add("This is (good)", True)
Tests.Add("This (is (good))", True)
Tests.Add("This is good", True)
Tests.Add("This is (bad))", False)
Tests.Add("This is (bad", False)
Tests.Add("This is bad)", False)
Tests.Add("This is bad)(", False)
For Each T In Tests
Console.WriteLine(TestStringParens(T.Key) = T.Value)
Next
Here is an example of how you use the mid function to loop through a string
Function checkPar(s As String) As Boolean
Dim i As Integer
Dim parCounter As Integer
parCounter = 0
For i = 1 To Len(s)
If Mid(s, i, 1) = "(" Then
parCounter = parCounter + 1
ElseIf Mid(s, i, 1) = ")" Then
parCounter = parCounter - 1
End If
If parCounter < 0 Then Exit For
Next
If parCounter <> 0 Then
checkPar = False
Else
checkPar = True
End If
End Function

Find files with filename filter

I am using VB.net VS2012 and am having trouble with getting a list of files with a filter.
Here is my code:
Public Function SearchAndAddToListWithFilter(ByVal path As String, ByVal Recursive As Boolean, arrayListOfFilters As ArrayList, ByRef listOfFiles As List(Of FileInfo))
If Not Directory.Exists(path) Then Exit Function
Dim initDirInfo As New DirectoryInfo(path)
For Each oFileInfo In initDirInfo.GetFiles
Application.DoEvents()
For x = 0 To arrayListOfFilters.Count - 1
If (oFileInfo.Name Like arrayListOfFilters(x)) Then
listOfFiles.Add(oFileInfo)
End If
Next
Next
If Recursive Then
For Each oDirInfo In initDirInfo.GetDirectories
SearchAndAddToListWithFilter(oDirInfo.FullName, True, arrayListOfFilters, listOfFiles)
Next
End If
End Function
And here is an example of how to use it:
Dim stringFilterList As String = "*.mp3, *.docx, *.mp3, *.txt"
Dim arrayListOfFilenameFilters As New ArrayList(stringFilterList.Split(","))
Dim stringFolderPath As String = "C:\temp\folder\"
Dim booleanSearchSubFolders As Boolean = True
Dim listOfFilesFoundViaSearch As New List(Of FileInfo)
SearchAndAddToListWithFilter(stringFolderPath, booleanSearchSubFolders, arrayListOfFilenameFilters, listOfFilesFoundViaSearch)
For x = 0 To listOfFilesFoundViaSearch.Count - 1
MsgBox(listOfFilesFoundViaSearch(x).FullName)
Next
For some reason, the code only adds the files to the list that satisy the first condition in the list of filters.
Can I please have some help to get this code working?
Thank you.
Functions return values, and passing a value ByRef is NOT the way to do it.
The following function will work:
Private Function SearchAndAddToListWithFilter(ByVal path As String, ByVal filters As String(), ByVal searchSubFolders As Boolean) As List(Of IO.FileInfo)
If Not IO.Directory.Exists(path) Then
Throw New Exception("Path not found")
End If
Dim searchOptions As IO.SearchOption
If searchSubFolders Then
searchOptions = IO.SearchOption.AllDirectories
Else
searchOptions = IO.SearchOption.TopDirectoryOnly
End If
Return filters.SelectMany(Function(filter) New IO.DirectoryInfo(path).GetFiles(filter, searchOptions)).ToList
End Function
and to use this function:
Dim filters As String() = {"*.mp3", "*.docx", "*.bmp", "*.txt"}
Dim path As String = "C:\temp\folder\"
Dim foundFiles As List(Of IO.FileInfo) = SearchAndAddToListWithFilter(path, filters, True)
The solution provided by #Steve really shows the .NET way of doing the task.
However I used a recursive solution with possible definitions of maximum depth and/or duration. For completeness of this topic, I want to post the code:
''' <summary>
''' Search files in directory and subdirectories
''' </summary>
''' <param name="searchDir">Start Directory</param>
''' <param name="searchPattern">Search Pattern</param>
''' <param name="maxDepth">maximum depth; 0 for unlimited depth</param>
''' <param name="maxDurationMS">maximum duration; 0 for unlimited duration</param>
''' <returns>a list of filenames including the path</returns>
''' <remarks>
''' recursive use of Sub dirS
'''
''' wallner-novak#bemessung.at
''' </remarks>
Public Shared Function dirRecursively(searchDir As String, searchPattern As String, _
Optional maxDepth As Integer = 0, _
Optional maxDurationMS As Long = 0) As List(Of String)
Dim fileList As New List(Of String)
Dim depth As Integer = 0
Dim sw As New Stopwatch
dirS(searchDir, searchPattern, maxDepth, maxDurationMS, fileList, depth, sw)
Return fileList
End Function
''' <summary>
''' Recursive file search
''' </summary>
''' <param name="searchDir">Start Directory</param>
''' <param name="searchPattern">Search Pattern</param>
''' <param name="maxDepth">maximum depth; 0 for unlimited depth</param>
''' <param name="maxDurationMS">maximum duration; 0 for unlimited duration</param>
''' <param name="fileList">Filelist to append to</param>
''' <param name="depth">current depth</param>
''' <param name="sw">stopwatch</param>
''' <param name="quit">boolean value to quit early (at given depth or duration)</param>
''' <remarks>
''' wallner-novak#bemessung.at
''' </remarks>
Private Shared Sub dirS(searchDir As String, searchPattern As String, _
Optional maxDepth As Integer = 0, _
Optional maxDurationMS As Long = 0, _
Optional ByRef fileList As List(Of String) = Nothing, _
Optional ByRef depth As Integer = 0, _
Optional ByRef sw As Stopwatch = Nothing, _
Optional ByRef quit As Boolean = False)
If maxDurationMS > 0 Then
If depth = 0 Then
sw = New Stopwatch
sw.Start()
Else
If sw.ElapsedMilliseconds > maxDurationMS Then
quit = True
Exit Sub
End If
End If
End If
If maxDepth > 0 Then
If depth > maxDepth Then
quit = True
Exit Sub
End If
End If
' check if directory exists
If Not Directory.Exists(searchDir) Then
Exit Sub
End If
' find files
For Each myFile As String In Directory.GetFiles(searchDir, searchPattern)
fileList.Add(myFile)
Next
' recursively scan subdirectories
For Each myDir In Directory.GetDirectories(searchDir)
depth += 1
dirS(myDir, searchPattern, maxDepth, maxDurationMS, fileList, depth, sw, quit)
If quit Then Exit For
depth -= 1
Next
End Sub
ListView1.Items.Clear()
For Each files As String In System.IO.Directory.GetFiles(cmb_Drives.SelectedItem.ToString, txtSearch.Text)
Dim ico As Icon = System.Drawing.Icon.ExtractAssociatedIcon(files)
ImageList1.Images.Add(ico)
Dim list As ListViewItem = New ListViewItem(My.Computer.FileSystem.GetFileInfo(files).FullName, ImageList1.Images.Count - 1)
ListView1.Items.Add(list)
Next

Improving recursive Active Directory function

I'm hoping to improve the performance of the below as well as return the GUID of each user.
I've converted and modified the code found here for searching through groups recursively to get all the members and their details and adding them to a class collection. However I also need to capture the user's managers details so I'm calling the AD twice for each user. This doesn't seem efficient as many of the users will have the same manager. It would seem logical to get the distinct manager details from the collection class and call only these, then replace them wherever they occur in the collection. I don't know the best way to do this however - still fairly new to all this ;)
I'd also like to be able to get the user's GUID, I've tried accessing it directly as a property of the collection, but it doesn't return anything.
Here's my code, I'd really appreciate any comments/suggestions :) - or any bad habits I have in general pointing out! ;)
I'm using vs2005 and .Net 2.0
Public Class ADCLass
''' <summary>
''' Calls recursive function to return users in group
''' </summary>
''' <param name="DistListAlias">CN for the Group</param>
''' <returns>Collection of class holding user details</returns>
''' <remarks></remarks>
Public Function GetDistListUsers(ByVal DistListAlias As String) As Collection(Of ADMembers)
Dim path As String = "LDAP://DC=systems,DC=Private"
Dim filter As String
Dim filterFormat As String = "(cn={0})"
Dim sAMAccountFilter As String
filter = String.Format(filterFormat, DistListAlias)
Dim properties As PropertyCollection = GetPropertiesForEntry(path, filter)
sAMAccountFilter = "(|(ObjectClass=Group)(objectCategory=user))"
Dim groupMembers As Collection(Of ADMembers) = New Collection(Of ADMembers)
If Not IsNothing(properties) Then
Dim sAMAccountTypes As Collection(Of Integer) = New Collection(Of Integer)
groupMembers = GetUsersInGroup(properties, groupMembers, sAMAccountFilter)
End If
Return groupMembers
End Function
#Region "GetUsersInGroup"
''' <summary>
''' Recursive function to list all users in group and sub group
''' Returns the sAMAccountName for the Managers
''' </summary>
''' <param name="Properties">Group Properties</param>
''' <param name="groupMembers">Collection fo Users</param>
''' <param name="filter"></param>
''' <returns>Collection of class holding user details</returns>
''' <remarks></remarks>
Private Function GetUsersInGroup(ByVal Properties As PropertyCollection, ByVal groupMembers As Collection(Of ADMembers), ByVal filter As String)
Dim pathFormat As String = "LDAP://{0}"
Dim memberIdx As String = "member"
Dim sAMAccountNameIdx As String = "sAMAccountName"
Dim sAMAccountTypeIdx As String = "sAMAccountType"
Dim personnelNumberIdx As String = "extensionAttribute4"
Dim TelNo As String
Dim prop As Object
Dim managerID As String
Dim manColl As PropertyCollection
If Not IsNothing(Properties(memberIdx)) Then
'Loop through found Members
For Each prop In Properties(memberIdx)
Dim distinguishedName As String = prop.ToString
Dim path As String = String.Format(pathFormat, distinguishedName)
Dim childProperties As PropertyCollection = GetPropertiesForEntry(path, filter)
If Not IsNothing(childProperties) Then
'Check that this is a user
If childProperties(sAMAccountTypeIdx).Value = 805306368 Then
'GetManager ID
managerID = childProperties("manager").Value.ToString
manColl = GetPropertiesForEntry(String.Format(pathFormat, managerID), filter)
managerID = manColl(sAMAccountNameIdx).Value.ToString
'Get Phone Number, if telephone number is null, check mobile, if null
'return ""
If Not IsNothing(childProperties("telephoneNumber").Value) Then
TelNo = childProperties("telephoneNumber").Value.ToString
Else
If Not IsNothing(childProperties("mobile").Value) Then
TelNo = childProperties("mobile").Value.ToString
Else
TelNo = ""
End If
End If
'Add the Properties to the class collection
groupMembers.Add(New ADMembers(childProperties(sAMAccountNameIdx).Value.ToString, _
childProperties("cn").Value.ToString, _
managerID, _
childProperties("Title").Value.ToString, _
TelNo, _
childProperties("mail").Value.ToString))
Else
'Found a group - recurse
GetUsersInGroup(childProperties, groupMembers, filter)
End If
End If
Next
End If
Return groupMembers
End Function
#End Region
#Region "GetPropertiesForEntry"
''' <summary>
''' Gets properties for given user in AD
''' </summary>
''' <param name="path">Distinguished AD name</param>
''' <param name="filter"></param>
''' <returns>Property collection for given user</returns>
''' <remarks></remarks>
Private Function GetPropertiesForEntry(ByVal path As String, ByVal filter As String) As PropertyCollection
Dim rootEntry As New DirectoryEntry(path)
Dim searcher As New DirectorySearcher(rootEntry)
With searcher
.Filter = filter
.PageSize = 5
.ServerTimeLimit = New TimeSpan(0, 0, 30)
.ClientTimeout = New TimeSpan(0, 10, 0)
End With
Dim result As SearchResult = searcher.FindOne
Return result.GetDirectoryEntry.Properties
End Function
#End Region
End Class
Code I am using as per JPBlancs's suggestion, whilst this works, it is much slower than my original, am I implementing it incorreclty?
Public Sub GetPropertiesForEntry()
Dim rootEntry As New DirectoryEntry("LDAP://DC=d1,DC=d2")
Dim searcher As New DirectorySearcher(rootEntry)
With searcher
.Filter = "(&(memberof:1.2.840.113556.1.4.1941:=CN=grp1,OU=Messaging Groups,OU=Groups,DC=d1,DC=d2)(objectCategory=user))"
.SearchScope = SearchScope.Subtree
.PropertiesToLoad.Add("cn")
.PageSize = 100
.ServerTimeLimit = New TimeSpan(0, 0, 30)
.ClientTimeout = New TimeSpan(0, 10, 0)
End With
Dim results As SearchResultCollection = searcher.FindAll()
For Each result As SearchResult In results
Debug.Print(result.Properties("cn").Item(0).ToString)
Next
End Sub
Can you have a look to Finding users that are members of two active directory groups. You'll find a method using LDAP_MATCHING_RULE_IN_CHAIN to collect recursively users from a group in one query.
As far as th GUID is concerned don't forget list the attribute you want the query to return. Be careful, as far as I remember the GUID will return in an INT array.
dsLookFor.PropertiesToLoad.Add("objectGUID")