I'm writing a program that creates new folders and moves the old folder to an archive location.
I need to be able to compare the last three digits of a folder path to see if it's "999", for example a folder will be called "1950-1999" and this will need a new parent folder.
Code so far:
Dim stringreader As String
Dim path As List(Of String)
Private Sub Archive_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Loads a text file at the given location, to read to.
fileReader = My.Computer.FileSystem.OpenTextFileReader("C:\Data\Test\Foldercreation.txt")
'Set stringreader as the read line from the file
stringreader = fileReader.ReadLine()
path = System.IO.Directory.GetDirectories(stringreader).ToList
path.Sort()
foldtoarchtxt.Text = path(0)
'closes the file
fileReader.Close()
As you can see I have got the folder path and stored it in a list (which is displayed to the user as well hence the text output).
I just don't know how to get VB.NET to always look at the last three digits on the right. One note, this will get to 100000's and maybe even 1000000 i.e. 100950-100999 so it can't be based on position from the left.
Consider using String.Substring:
Retrieves a substring from this instance. The substring starts at a specified character position and continues to the end of the string.
If path(0).Substring(path(0).Length - 3)) = "999" Then
...
End If
As an example:
Dim s As String = "100950-100999"
Debug.WriteLine(s.Substring(s.Length - 3))
Output:
999
You can use Strings.Right(string, n) to get the last n characters of string:
Returns a string containing a specified number of characters from the right side of a string.
Related
I have a text file which contains the same string of characters in different lines. I read the file using this code:
Dim readTexte() As String = File.ReadAllLines(OuvrirFichier, Encoding.UTF8)
Dim t As String
For Each t In readTexte
If t.Contains(TreeView1.SelectedNode.Text) Then
TextBox2.Text = Trim(t.Substring(0, 18))
TextBox1.Text = Trim(t.Substring(18, 90))
TextBox4.Text = Trim(t.Substring(107, 120))
End If
Next
However, I have a problem because when cutting and reading these strings. The code is not able to choose the right line to match the TreeView node, because it identifies several equally perfect strings.
For example, the first line contains 3 substrings (fixed width fields):
Saint, Augustine, and Doctor of the Church.
The second line contains three sub-strings as well, slightly different:
Saint, Monica, and mother of Saint Augustine
When I want to read, my code gives me two Augustines, and mixes Augustine and Monique! The TextBox2 contains the string contained in the treeview.
How can I fix this?
The treeview is created as simply as possible, thus:
Dim readText () As String = File.ReadAllLines (OpenFile,
Encoding.UTF8)
Dim s As String
For Each s In readText
TextBox2.Text = Trim (s.Substring (0, 18))
TextBox1.Text = Trim (s.Substring (18, 90))
TextBox4.Text = Trim (s.Substring (107, 120))
Dim node As TreeNode = Me.TreeView1.Nodes (0)
TreeView1.Nodes (0) .Nodes.Add (New TreeNode (TextBox1.Text))
Next
We need to know more about how the TreeView is built before we can answer this. It's possible there is simply not enough data associated with the TreeView right now, and the solution will be in a completely different area of the code.
However, I can provide some notes. First, reading a file is one of the slowest things possible to do in a computer. We already see this is small enough to fit in memory; if it's also reasonably stable (doesn't change often), you can save significant work by loading to the array once when the program starts.
Next, I wouldn't keep just a simple array of strings. Instead, I'd parse the data into separate fields right at load. A Tuple, Class, or even string array can all work.
Finally, this code will continue looping even after if finds a match. I'd have a way to stop once we find what we're looking for.
Put it all together like this:
'Create a set of Tuples. Could also use a class here.
Dim readTexte() As IEnumerable(Of (String, String, String)) =
File.ReadLines(OuvrirFichier, Encoding.UTF8).
Select(Function(line) (Trim(line.SubString(0, 18)), Trim(line.SubString(18,90)), Trim(line.SubString(107,120))) )
'Search the collection for the first match
Dim result = readTexte.First(Function(record) TreeView1.SelectedNode.Text.Equals(record.Item1))
TextBox2.Text = result.Item1
TextBox1.Text = result.Item2
TextBox4.Text = result.Item3
Again, this doesn't solve your matching problem, because the question doesn't contain the information we need to help do that. Please edit the question to include more details on how the TreeView is created.
Hello world!
I've ran into a problem. I am getting directories contained in certain path and I need to separate the path VB.NET's giving me (like this:
"D:\ApplicationFolder\Addons\Pack_1",
"D:\ApplicationFolder\Addons\Pack_2" ...
Only into this:
"Pack_1", "Pack_2"
So far I've tried this, but I can't get into a solution, I am lost...
Dim ADDONPACKS_DIRECTORIES As String() = Directory.GetDirectories(ADDONS_PATH) ' GETTING ALL DIRECTORIES (PATHS) IN THIS PATH
For Each ADDONPACKS_DIRECTORY In ADDONPACKS_DIRECTORIES ' TRYING TO SPLIT FULL PATH OF THESE DIRECTORIES TO GET ONLY THE NAME OF THESE DIRECTORIES
ADDONPACKS_DIRECTORY.Split()
Dim ADDONPACKS_LENGTH As Integer = ADDONPACKS_DIRECTORY.Length()
MsgBox(ADDONPACKS_DIRECTORY(2))
Next
' Here I want to assign names of these directories onto a label. But the fields only show letters instead of the path segments.
Addonpack1.Text = ADDONPACKS_DIRECTORIES(0)
Addonpack2.Text = ADDONPACKS_DIRECTORIES(1)
Addonpack3.Text = ADDONPACKS_DIRECTORIES(2)
Addonpack4.Text = ADDONPACKS_DIRECTORIES(3)
Addonpack5.Text = ADDONPACKS_DIRECTORIES(4)
'Addonpack6.Text = ADDONPACKS_DIRECTORY(5)
Any ideas? I really appreciate further help.
string.Split() is a Function: it returns a value.
Here: ADDONPACKS_DIRECTORY.Split(), you are splitting the string using the default separator (a white space) but the result is not assigned to anything, so it's lost (but it wouldn't be useful anyway).
This: MsgBox(ADDONPACKS_DIRECTORY(2)), will show only one char of the current Directory path. A string is a collection (an array) of chars. You're asking to show the 3rd.
If you think you won't need the complete directory listing anymore, you could Split the initial collection directly:
Dim ADDONPACKS_DIRECTORIES As String() = Directory.GetDirectories(ADDONS_PATH).
Select(Function(d) d.Split("\"c).Last()).ToArray()
Addonpack1.Text = ADDONPACKS_DIRECTORIES(0)
'(...)
If you instead are going to use that collection of Paths later, you could Split each path and assign the result to each TextBox.Text property, leaving the original collection untouched:
Addonpack1.Text = ADDONPACKS_DIRECTORIES(0).Split("\"c).Last()
Addonpack2.Text = ADDONPACKS_DIRECTORIES(1).Split("\"c).Last()
'(...)
Do you know beforehand how many Addons you will have?
If not, a TextBox for each path might not be the right object to use as the output.
Maybe, you could use a single multiline TextBox. It's Lines() property will hold the array of all the Sub-Paths you appended.
Using the first snippet, it could be something like this:
For Each subpath As String In ADDONPACKS_DIRECTORIES
TextBox1.AppendText(subpath & Environment.NewLine)
Next
Note:
As LarsTech noted in the comments, you could use Path.GetFileName() insted of splitting the path using the path separator.
It would work with both file names and path names, because Path.GetFileName returns the substring of a path when it first finds a path separator, parsing the string from the end to the start, no matter if the substring represents a path or a file name.
Addonpack1.Text = Path.GetFileName(ADDONPACKS_DIRECTORIES(0))
'(...)
I have a text file called "Games.txt" that looks like this:
Call of Duty: 50
Assasins Creed: 23
Watch Dogs: 140
If i want to know the number of "Assasins Creed" How would I get that?
What i have tried so far:
I have tried finding it by knowing the line, length of the string. Then reading that and removing the first 15 charachters ("Assasins Creed:") That would leave me with: 23. But this is a pretty bad way of doing it, and it needs me to know the exact line.
What would a better solution be?
If you only want to get the values for "Assasins Creed", with Regex, you can do something like this:
Dim contents As String = IO.File.ReadAllText(filePath)
Dim re As New Regex("(Assasins Creed):\s*(\d+)")
Dim m As Match = re.Match(contents)
If m.Success Then
Console.WriteLine($"The number of '{m.Groups(1).Value}' games is {m.Groups(2).Value}.")
End If
Output:
The number of 'Assasins Creed' games is 23.
If you need to retrieve the values for all games, you can adjust the above code to something like this:
Dim contents As String = IO.File.ReadAllText(filePath)
Dim re As New Regex("(.+):\s*(\d+)")
Dim matches As MatchCollection = re.Matches(contents)
For Each m As Match In matches
Console.WriteLine($"The number of '{m.Groups(1).Value}' games is {m.Groups(2).Value}.")
Next
Output:
The number of 'Call of Duty' games is 50.
The number of 'Assasins Creed' games is 23.
The number of 'Watch Dogs' games is 140.
Notes:
Remember to replace filePath with the actual path of your text file.
You need to add Imports System.Text.RegularExpressions at the top of your class in order to be able to use the Regex class.
Getting started in this game can be tricky because lots of people expect beginners to do their own research and understand it before offering a simple solution and explanation as to why it works. Giving an absolute beginner a regex statement looks more like someone flexing their ego than offering assistance, so if you're looking for a solution that a beginner can not only use, but also have a hope of understanding (and possibly utilise again elsewhere in their code), then the split command could be used like this:
If you Import System.IO it be more useful than regular expressions at this stage I believe
'Place this at the top of the code block above the Class statement
Imports System.IO 'This provides access to File.ReadAllLines (Input/Output)
Then you could create a function which retrieves the information you need and returns the result like this:
''' <summary>
''' Returns the game value plus the index in the list
''' </summary>
''' <param name="FilePath">Full path of the file</param>
''' <param name="Game">Name of the game to return</param>
''' <param name="index">(Optional) Index of the position in the list (-1 if not found)</param>
''' <returns></returns>
Function GameValue(ByVal FilePath As String, ByVal Game As String, Optional ByRef Index As Integer = -1) As Integer
'This returns the file as an array of lines
Dim Lines() As String = File.ReadAllLines(FilePath)
'This loop will iterate through each item in the array
For i As Integer = 0 To Lines.Length - 1
'This turns each line into an array of name and value (either side of the colon + space)
Dim Segments() As String = Lines(i).Split({": "}, StringSplitOptions.None)
'This will bypass any blank lines or lines without ": "
If Segments.Length > 1 Then
'This tries to match the first segment against the name of the game
If Segments(0) = Game Then
'This handles a successful match
'Store the index of the position of the game in the list
Index = i
'Convert final value into Integer and return result
Return Convert.ToInt32(Segments(1))
End If
End If
Next i
'If no correct match for Game is found, 0 is returned
Return 0
End Function
When you want to call the function, you can do this from within a button click for example:
Private Sub cmdApply_Click(sender As Object, e As EventArgs) Handles cmdApply.Click
'Specify the filename however you like
Dim f As String = "C:\ProgramData\game.txt"
'Specify the name of game however you like
Dim g As String = "Watch Dogs"
'Start an index at -1 (This will get modified by the function if the result is found)
Dim i As Integer = -1
'Use the function to return process a result (value)
Dim v As Integer = GameValue(f, g, i)
Console.WriteLine("Game: " & g)
Console.WriteLine("Value: " & v)
Console.WriteLine("Index: " & i)
End Sub
Sometimes, simple things can actually be pretty complicated once you really look into how to do it. And like most things, there's always another way to go about it.
If you try this code you should be able to take out a few things:
How to make and use a function
How to add xml tags to functions to make calling them easier to understand
One method of utilising ByRef to affect the value of a variable declared elsewhere (index)
How to read a text file and process its contents
How to split a string into an array for independent processing
How to convert a string into an integer
Things to note:
An error will occur if file path or name does not exist
An error might occur if Game: xys value is not a number
An error will not occur if the line does not contain ": " because we tested for that
In this case, the game name is case sensitive. You could use Game.ToUpper and Segments(0).ToUpper to convert both values to uppercase when checking if they match if you want to remove case sensitivity
Im sure someone out there can help, im totally new to coding but getting into it and really enjoying. I know this is such a simple question out there for you folks but i have the following, I load a spread sheet of strings (2 columns) into a datagridview the reason i do this because there is over 100,000 find and replaces and these will generally sit within and existing string when searching, then from there i want to simply search a txt file and find and replace a number of strings in it. So it would check each row in a datagrid take from column 1 the find and use column 2 to replace then outputs the string to another txt file once the find and replace has taken place. My current results are that it just takes what was in the first file and copies without replacing in the second find.
Any assistance is gratefully received, many thanks.
Please see below my amateur code:-
Private Sub CmdBtnTestReplace_Click(sender As System.Object, e As System.EventArgs) Handles CmdBtnTestReplace.Click
Dim fName As String = "c:\backup\logs\masterUser.txt"
Dim wrtFile As String = "c:\backup\logs\masterUserFormatted.txt"
Dim strRead As New System.IO.StreamReader(fName)
Dim strWrite As New System.IO.StreamWriter(wrtFile)
Dim s As String
Dim o As String
For Each row As DataGridViewRow In DataGridView1.Rows
If Not row.IsNewRow Then
Dim Find1 As String = row.Cells(0).Value.ToString
Dim Replace1 As String = row.Cells(1).Value.ToString
Cursor.Current = Cursors.WaitCursor
s = strRead.ReadToEnd()
o = s.Replace(Find1, Replace1)
strWrite.Write(o)
End If
Next
strRead.Close()
strWrite.Close()
Cursor.Current = Cursors.Default
MessageBox.Show("Finished Replacing")
End Sub
1. What you are doing is :
creating a StreamReader whose purpose is to read chars from a File/Stream in sequence.
creating a StreamWriter whose purpose is to add content to a File/Stream.
then looping
a) read the remaining content of file fName and put it in s
b) replace words from s and put the result in o
c) add o to the existing content of the file wrtFile
then the usual closing of the stream reader/writer...
But that doesn't work because, on the secund iteration of the loop, strRead is already at the end of your loaded file, then there is nothing to read anymore, and s is always an empty string starting from the secund iteration.
Furthermore, because s is empty, o will be empty aswell.
And last of all, even if you manage to re-read the content of the file and replace the words, strWrite will not clear the initial content of the output file, but will write the resulting replaced string (o) after the previously updated content of the file.
2. Since you loaded the content of the file in a string (s = strRead.ReadToEnd()), why don't you :
load that s string before the For-Next block
loop the datagridview rows in a For-Next block
replace using the pair Find1/Replace1 s = s.Replace(Find1, Replace1)
then, save the content of s in the targeted file outside the For-Next block
3. However, improving your understanding of how streams work, what should be considered and what are forbidden is a bit outside the scope of SO I think; such documentation could be found/gathered on the MSDN page or with the help of your friend : google. The same applies for finding out/thinking of how you should arrange your code, how to achieve your goal.Let's take an example :
' Content of your file :
One Two Three Four Five Six
' Content of your DataGridView :
One | Two
Two | Three
Three | Four
Four | Five
Five | Six
Six | Seven
The resulting replacement text at the end of a similar routine as yours will be :
Seven Seven Seven Seven Seven Seven ' :/
' while the expected result would be :
Two Three Four Five Six Seven
And that's because of the iteration : already replaced portions of your file (or loaded file content) could get replaced again and again. To avoid that, either :
split the loaded content in single words, and use a "replaced" flag for each word (to avoid replacing that word more than once)
or preload all the pair Find/Replace, and parse the file content in sequence once, replacing that instance when required.
So, before using an interesting object in the framework :
you should know what it does and how it behaves
otherwise -> read the documentation
otherwise -> create a minimalistic test solution which purpose is to brute force testings on that particular object to debunck all its powers and flaws.
So, like I said in 2., move those ReadAllText() and Write() outside the For/Next block to start from and have a look at the resulting output (Ask specific questions in comments when google can't answer) Then if you're OK with it even if issue like the One Two Three example above could occur, then voila ! Otherwise, use google to gather more examples on "splitting text in words" and reformating the whole, have some tries, then get back here if you're stuck on precise issues.
I have a program I am creating and when i go to remove blank lines this is how I go about it.
For Each i As ListViewItem In lvSongs.SelectedItems
lvSongs.Items.Remove(i)
CurrentSong = i.SubItems(4).Text 'This is the Songs Path
files = File.ReadAllText("songs.txt") 'The songs path's are in the txt
'I am using this as a list of lines i want to keep in
'the txt file.
Dim linesToKeep As New List(Of String)
For Each line As String In files 'Goes through lines
If Not line.Contains(CurrentSong) Then 'checks to see if line is Current song
linesToKeep.Add(line) 'Adds line if its not CurrentSong to the list
End If
Next
File.WriteAllLines("songs.txt", linesToKeep.ToArray())
but when i go to check the txt document, i get this:
EXAMPLE (but written horizontally, each letter being on a new line)
in the text file my friend says its because i have lines set as a string instead of a string().
Thanks for anyhelp!
Ask for more information if im confusing you...
The problem is you are using the ReadAllText API. This returns a String not a String() hence when you later iterate you are iterating over every character in the file, not every line. To fix this use the ReadAllLines API which returns a String()
files = File.ReadAllLines("songs.txt")
Note I can't tell if files is an implicitly declared local or a field. If it's a field typed to String you will need to change the type to String().