Visual Basic (2010) - Using variables in embedded text files? - vb.net

Ive always been able to just search for what I need on here, and I've usually found it fairly easily, but this seems to be an exception.
I'm writing a program in Visual Basic 2010 Express, it's a fairly simple text based adventure game.
I have a story, with multiple possible paths based on what button/option you choose.
The text of each story path is saved in its own embedded resource .txt file. I could just write the contents of the text files straight into VB, and that would solve my problem, but that's not the way I want to do this, because that would end up looking really messy.
My problem is that I need to use variable names within my story, here's an example of the contents of one of the embedded text files,
"When "+playername+" woke up, "+genderheshe+" didn't recognise "+genderhisher+" surroundings."
I have used the following code to read the file into my text box
Private Sub frmAdventure_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim thestorytext As String
Dim imageStream As Stream
Dim textStreamReader As StreamReader
Dim assembly As [Assembly]
assembly = [assembly].GetExecutingAssembly()
imageStream = assembly.GetManifestResourceStream("Catastrophe.CatastropheStoryStart.png")
textStreamReader = New StreamReader(assembly.GetManifestResourceStream("Catastrophe.CatastropheStoryStart.txt"))
thestorytext = textStreamReader.ReadLine()
txtAdventure.Text = thestorytext
End Sub
Which works to an extent, but displays it exactly as it is in the text file, keeps the quotes and the +s and the variable names instead of removing the quotes and the +s and replacing the variable names with what's stored within the variables.
Can anyone tell me what I need to change or add to make this work?
Thanks, and apologies if this has been answered somewhere and I just didn't recognise it as the solution or didn't know what to search to find it or something.

Since your application is compiled, you cannot just put some of your VB code in the text file and have it executed when it is read.
What you can do, and what is usually done, is that you leave certain tags inside your text file, then locate them and replace them with the actual values.
For example:
When %playername% woke up, %genderheshe% didn`t recognise %genderhisher% surroundings.
Then in your code, you would find all the tags:
Dim matches = Regex.Matches(thestorytext, "%(\w+?)%")
For Each match in matches
' the tag name is now in: match.Groups(1).Value
' replace the tag with the value and replace it back into the original string
Next
Of course the big problem still remains - which is how to fill in the actual values. Unfortunately, there is no clean way to do this, especially using any local variables.
You can either manually maintain a Dictionary of tag names and their values, or use Reflection to get the values directly at the runtime. While it should be used carefully (speed, security, ...), it will work just fine for your case.
Assuming you have all your variables defined as properties in the same class (Me) as the code that reads and processes this text, the code will look like this:
Dim matches = Regex.Matches(thestorytext, "%(\w+?)%")
For Each match in matches
Dim tag = match.Groups(1).Value
Dim value = Me.GetType().GetField(tag).GetValue(Me)
thestorytext = thestorytext.Replace(match.Value, value) ' Lazy code
Next
txtAdventure.Text = thestorytext
If you don't use properties, but only fields, change the line to this:
Dim value = Me.GetType().GetField(tag).GetValue(Me)
Note that this example is rough and the code will happily crash if the tags are misspelled or not existing (you should do some error checking), but it should get you started.

Related

VB.Net Read multi column text file and load into ListBox

First, I am not a programmer, I mainly just do simple scripts however there are somethings that are just easier to do in VB, I am pretty much self taught so forgive me if this sounds basic or if I can't explain it to well.
I have run into an issue trying to load a multi-column text file into a list box. There are two separate issues.
First issue is to read the text file and only grab the first column to use in the listbox, I am currently using ReadAllLines to copy the text file to a string first.
Dim RDPItems() As String = IO.File.ReadAllLines(MyDocsDir & "\RDPservers.txt")
However I am having a difficult time finding the correct code to only grab the first Column of this string to put in the listbox, if I use the split option I get an error that "Value of type '1-dimensional array of String' cannot be converted to 'String'"
The code looked like
frmRDP.lstRDP.Items.Add() = Split(RDPItems, ";", CompareMethod.Text)
This is the first hurdle, the second issue is what I want to do is if an item is selected from the List box, the value of the second column gets pulled into a variable to use.
This part I'm not even sure where to begin.
Example data of the text file
Server1 ; 10.1.1.1:3389
Server2 ; 192.168.1.1:8080
Server3 ; 172.16.0.1:9833
.....
When it's working the application will read a text file with a list of servers and their IPs and put the servers in a listbox, when you select the server from the listbox it and click a connect button it will then launch
c:\windows\system32\mstsc.exe /v:serverip
Any help would be appreciated, as I can hard code a large list of this into the VB application it would be easier to just have a text file with a list of servers and IPs to load instead.
The best practise for this would probably be to store your "columns" in a Dictionary. Declare this at class level (that is, outside any Sub or Function):
Dim Servers As New Dictionary(Of String, String)
When you load your items you read the file line-by-line, adding the items to the Dictionary and the ListBox at the same time:
Using Reader As New IO.StreamReader(IO.Path.Combine(MyDocsDir, "RDPservers.txt")) 'Open the file.
While Reader.EndOfStream = False 'Loop until the StreamReader has read the whole file.
Dim Line As String = Reader.ReadLine() 'Read a line.
Dim LineParts() As String = Line.Split(New String() {" ; "}, StringSplitOptions.None) 'Split the line into two parts.
Servers.Add(LineParts(0), LineParts(1)) 'Add them to the Dictionary. LineParts(0) is the name, LineParts(1) is the IP-address.
lstRDP.Items.Add(LineParts(0)) 'Add the name to the ListBox.
End While
End Using 'Dispose the StreamReader.
(Note that I used IO.Path.Combine() instead of simply concatenating the strings. I recommend using that instead for joining paths together)
Now, whenever you want to get the IP-address from the selected item you can just do for example:
Dim IP As String = Servers(lstRDP.SelectedItem.ToString())
Hope this helps!
EDIT:
Missed that you wanted to start a process with it... But it's like charliefox2 wrote:
Process.Start("c:\windows\system32\mstsc.exe", "/v:" & Servers(lstRDP.SelectedItem.ToString()))
Edit: #Visual Vincent's answer is way cleaner. I'll leave mine, but I recommend using his solution instead. That said, scroll down a little for how to open the server. He's got that too! Upvote his answer, and mark it as correct!
It looks like you're trying to split an array. Also, ListBox.Items.Add() works a bit differently than the way you've written your code. Let's take a look.
ListBox.Items.Add() requires that you provide it with a string inside the parameters. So you would do it like this:
frmRDP.lstRDP.Items.Add(Split(RDPItems, ";", CompareMethod.Text))
But don't do that!
When you call Split(), you must supply it with a string, not an array. In this case, RDPItems is an array, so we can't split the entire thing at once. This is the source of the error you were getting. Instead, we'll have to do it one item at a time. For this, we can use a For Each loop. See here for more info if you're not familiar with the concept.
A For Each loop will execute a block of code for each item in a collection. Using this, we get:
For Each item In RDPItems
Dim splitline() As String = Split(item, ";") 'splits the item by semicolon, and puts each portion into the array
frmRDP.lstRDP.Items.Add(splitline(0)) 'adds the first item in the array
Next
OK, so that gets us our server list put in our ListBox. But now, we want to open the server that our user has selected. To do that, we'll need an event handler (to know when the user has double clicked something), we'll have to find out which server they selected, and then we'll have to open that server.
We'll start by handling the double click by creating a sub to deal with it:
Private Sub lstRDP_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles lstRDP.MouseDoubleClick
Next, we'll get what the user has selected. Here, we're setting selection equal to the index that the user has selected (in this case, the first item is 0, the second is 1, and so on).
Dim selection As Integer = lstRDP.SelectedIndex
Lastly, we need to open the server. I'm assuming you want to do that in windows explorer, but if I'm mistaken please let me know.
Dim splitline() As String = Split(RDPItems(selection), ";")
Dim location As String = Trim(splitline(1))
We'll need to split the string again, but you'll notice this time I'm choosing the item whose location in the array is the same as the index of the list box the user has selected. Since we added our items to our listbox in the order they were added to our array, the first item in our listbox will be the first in the array, and so on. The location of the server will be the second part of the split function, or splitline(1). I've also included the Trim() function, which will remove any leading or trailing spaces.
Finally, we need to connect to our server. We'll use Process.Start() to launch the process.
Process.Start("c:\windows\system32\mstsc.exe", "/v:" & location)
For future reference, to first argument for Process.Start() is the location of the process, and the second argument is any argument the process might take (in this case, what to connect to).
Our final double click event handler looks something like this:
Private Sub lstRDP_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles lstRDP.MouseDoubleClick
Dim selection As Integer = lstRDP.SelectedIndex
Dim splitline() As String = Split(RDPItems(selection), ";")
Dim location As String = Trim(splitline(1))
Process.Start("c:\windows\system32\mstsc.exe", "/v:" & location)
End Sub
A final note: You may need to put
Dim RDPItems() As String = IO.File.ReadAllLines(MyDocsDir & "\RDPservers.txt")
outside of a sub, and instead just inside your class. This will ensure that both the click handler and your other sub where you populate the list box can both read from it.

How to check if a dictionary word is a part of a user input in vb?

I've coded a password analyser for a school project. I want it to be able to test if their password contains a dictionary word in any place. For example, kdghdcheesegjgjd would still be flagged because it contains cheese. Would I need to find a file containing a list of all dictionary words, or is their such a built-in function?
Thanks.
Most languages don't have any (human language) dictionaries built into them. You will need to find/make your own and have the program read from that file.
A personal tip is to make your own very short one for testing purposes (say 5 words) to see that the program reads and interprets the file properly.
As stated by #Jonas Olsson, there is no built-in dictionary in VB. You need to create them on your own. And making it is fairly easy, but I'll show easier way to solve your problem. First make a text file containing all the words you want your program to check if it contains that word. Then save it somewhere else, for the sake of my example, I'll create a text file containing the word "cheese". So:
Dim myFile As String = "D:\test.txt" //Location of my txt file
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim item() As String = File.ReadAllLines(myFile) //Reads whatever your txt file contains
//compares every line in your to text file to the password field
For Each line As String In item
If txtPassword.Text.Contains(line) Then
MessageBox.Show("Invalid password!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
Next
End Sub
Hope that helps! Or atleast it gave you an idea :))
You will have to find your own dictionary somewhere. I've used the The Gutenberg Webster's Unabridged Dictionary in the past myself because it's public domain. However, it is in a pretty raw form, and you'll likely have to do a lot of processing on it to get it in a shape that is usable to you.
There are likely other public domain or "open sourced" wordlists somewhere that you can use. I suggest a google search for "public domain english word list" or "free english word list" or similar searches. Then it's just a matter of reading in the file and doing your processing against it.

Formatting .readLine output for currency and right aligned

I am writing a simple program that writes input to a sequential access file and then reads them back and displays them in the list box using .readLine. The numbers need to be formatted for american currency and right aligned. Problem is i cant figure out how to properly write the .readLine to do that. i am working out of a text book, and still new to vb.net, so im looking for the simplest way to solve this problem without re-writing alot of it. The code i have tried is within the DO loop below:
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
'declare new inFile Varable as a streamreader object
Dim inFile As IO.StreamReader
'opens gross.txt for input
inFile = IO.File.OpenText("gross.txt")
'.Exists() searches /bin folder for gross.txt, returns a boolean value
If IO.File.Exists("gross.txt") Then
inFile = IO.File.OpenText("gross.txt")
'fill the list with the values
Do Until inFile.Peek = -1
lstContents.Items.Add(inFile.ReadLine.PadLeft(7, " ")).ToString("C2")
Loop
Else
MessageBox.Show("The file you have requested does not exist", "Gross Pay Project",
MessageBoxButtons.OKCancel, MessageBoxIcon.Error)
End If
End Sub
We can get this down to a single line:
lstContents.Items.AddRange(File.ReadAllLines("gross.txt").Select(Function(s) Double.Parse(s).ToString("C2").PadLeft(7)).ToArray())
Or in a more readable way, with the error-handling and method defintion back:
Private Sub btnDisplay_Click(sender As Object, e As EventArgs) Handles btnDisplay.Click
Try
lstContents.Items.AddRange( _
File.ReadAllLines("gross.txt").
Select(Function(s) Decimal.Parse(s).ToString("C2").PadLeft(7)).
ToArray() )
Catch ex As IOException
MessageBox.Show("Unable to open the file you requested", "Gross Pay Project",
MessageBoxButtons.OKCancel, MessageBoxIcon.Error)
End Try
End Sub
Now to explain this code. To begin with, I replaced your call to IO.File.Exists() with a Try/Catch block. File.Exists() only checks one reason a file might not open. It ignores other reasons like file permissions and process locking. Even when checking whether a file exists, the file system is volatile and you still have a race condition situation, where a file might be deleted in between when you check if it exists and when you go to open it. It's almost always better to just skip calling File.Exists() entirely and instead use the try/catch block to handle an exception if opening the file fails, as shown above.
Going into the Try/Catch block, I changed the code so that it uses AddRange() instead of adding one item at a time in a loop. This allows us to build an array with the items we want and update the UI in a single step. Building that array may seem like extra work, but .Net provides some features to help us. In this case, the File.ReadAllLines() method reads in the entire file in one step, so that we can start with an array right from the beginning. All we have to do is make the array have the right information.
To get the information we want in the array, I perform a projection or transformation of the existing data. To accomplish that, I used a LINQ select operator (or the .Select() extension method, in this case). The LINQ extension methods generally ask you to build an inline function. In the case of this use of the select operator, that inline function expects a string variable (s) that represents a single line in the original array. I then supply code to transform that original string into the format we need.
Each line in the file begins as a string value, but we know that the string variable holds pricing information... it will be numeric. The best way to transform numeric data is generally to convert it a number, which is what I do. I chose the Decimal type, because when working with money you almost always want to prefer Decimal over Double or Single. In this case, Double may have been okay, but Decimal will still work just fine. Once I have a numeric type like Decimal, I can use a Numeric Format String to get a string back that has the correct currency symbol and formatting. The original code did not work because you were trying to use the format string with a value that was already a string type. The format strings only work with numeric types, like the Decimal we have here. Now that I have a string with the correct text, all I need to do now is pad it so that it will be right-justified when shown in the list.
Finally, you will recall that the AddRange() method expects an array. The LINQ select operator does not produce an array. It produces something called an IEnumerable. This is a type that represents a sequence of some kind. Arrays are one kind of sequence, but they are not the only kind of sequence, and the LINQ system wants to be able to work with many different kinds of sequences. Thankfully, getting back to an array is easy: just call the ToArray() method.
You should definitely use a ListView instead of a listbox. I don't think you can right-align with listbox items.

vb.net Selecting values and their string values

I have a text file that looks like this:
32 bob
50 willy
32 sarah
50 john
I have loaded this text file into my application:
Private Sub browsebtn1_Click(sender As Object, e As EventArgs) Handles browsebtn1.Click
Dim filedialog As New OpenFileDialog 'openfiledialog1 is now filedialog'
filedialog.Filter = "Text Document|*.txt" 'filter the openfiledialogs file extension to txt only'
filedialog.Title = "Select Bosvark Log File.." 'openfiledialog title'
If filedialog.ShowDialog = Windows.Forms.DialogResult.OK Then 'if the file is chosen then..'
filepath1.Text = filedialog.FileName 'filepath1 text is file path of selected file'
RichTextBox1.LoadFile(filepath1.Text, RichTextBoxStreamType.PlainText) 'richtextbox1 retrieves the file path and displays the document'
End If
End Sub
What I want to do is then have a button where I click it and a new richtextbox will display the data from a value that I have given, For example I have a textbox and in that textbox I type "50" the new richtextbox will display this:
willy
john
I do not expect code, All I need is some sort of reference or guidance. But if you want to give code then thats fine. I have been searching for this answer everywhere but no luck, I am familiar with how it is supposed to work because when I write php code and I use mysql tables, you can write a query that says "SELECT FROM users WHERE username = $username". Is there a similar function in vb.net?
Of course VB.NET has a similar function, but, just like PHP, SELECT commands only work with a SQL database. There is no built-in support for executing SELECT commands on text files. If you do want to store the data in a SQL database, rather than a text file, so that you can execute SELECT commands, you'll need to look into either ADO.NET or LINQ to SQL.
If you do need to store the data as a text file, you can either parse the data yourself, for instance:
For Each line As String In File.ReadAllLines(filedialog.FileName)
Dim parts() As String = line.Split()
Dim number As String = parts(0)
Dim name As String = parts(1)
'Do something with the parsed values, such as storing them in a List, or Dictionary
Next
Or, you can use the TextFieldParser class which will parse the data for you. That will only work, though, if your file is in a format that is supported by that class.
In either case, you'll need to load the data into some sort of data-structure in memory, such as a DataTable, List, or Dictionary. It's impossible to say, with the limited information you've given, which data-structure makes the most sense for your particular situation. Once you have the data loading into a data-structure, then you can write a method which outputs either all of that data, or a subset of that data, to a RichTextBox, as necessary. How you do that will depend entirely on what data-structure you choose.

Easy way to remove warning messages after converting vb6 project to VB.NET

I have converted a VB6 project to VB.NET and am left with a large number of inline 'warning messages' such as "UPGRADE_WARNING: Couldn't resolve default property of object varJonSkeet" that I would like to get rid of. Is there a way to do this within Visual Studio 2008? Will it be easier to remove the warning messages with regex? I would prefer to do the removals one file at a time, but it isn't a dealbreaker.
Quick and simple fix if using VS 2008, use Find and Replace :
Open up the find options
Click 'use' and then select 'Wildcards'
In the 'Find what' put "'Upgrade Warning*" and leave the 'Replace with' blank
Click 'Replace All'
The best way to get rid of warnings is to address the suspicious code that the warnings complain about. That is, change the code such that it is no longer warning-worthy. Don't just seek to disable the generation of warnings altogether.
You'll need to provide more details about the specific warnings you're concerned about, and the accompanying code. But remember to search previous answers here first.
I see the warnings are actually text literally in your code, not messages issued in the compiler output. The way to get rid of those is to search for the keyword (UPGRADE_WARNING, I guess), consider whether the issue that it warns about has been addressed or is still a valid concern, fix the problem if there is one, and the delete that warning line. For example, does varJonSkeet have a default property, and if not, does it need one? Should you use to a non-default property instead? (You're not really asking how to delete a line of text, are you?)
If you've already gone through the whole file and determined that none of the warnings are valid, there's a quick way of removing all the warning lines.
grep -v UPGRADE_WARNING input_file.vb > output_file.vb
ren output_file.vb input_file.vb
If you don't already have grep on your system, then you don't have a complete development environment yet. Go get a copy. The -v option tells it to invert the search results, thus printing all lines that don't contain the search pattern. Those get written into the new file. Then replace the old file with the new one.
I believe he is saying that he wants to remove the inline comments from his code.
Fastest way is to perform a find in files for UPGRADE_WARNING: and remove them by hand.
Or,
You could create a new .Net program to iterate through each .vb file in your source directory and read them in using a StreamReader and then write them out 1 line at a time to the same file and as you go omit any lines containing UPGRADE_WARNING:.
If you do the second way you will be that much better for having done some more vb.net coding.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim FileName As String = "c:\form1.vb"
Dim SourceFile As System.IO.FileInfo = New FileInfo(FileName)
Dim SourceTextStream As System.IO.TextReader = SourceFile.OpenText()
Dim SourceFileContent() As String = Split(SourceTextStream.ReadToEnd(), vbCrLf)
SourceTextStream.Close()
Dim CurrentSourceLine As String
Dim CurrentSourceLineNumber As Long
Dim DestStream As StreamWriter = New StreamWriter(FileName)
Dim LogStream As StreamWriter = New StreamWriter(FileName + ".log")
For Each CurrentSourceLine In SourceFileContent
CurrentSourceLineNumber += 1
If InStr(CurrentSourceLine, "UPGRADE_WARNING") = 0 Then
DestStream.WriteLine(CurrentSourceLine)
Else
' Write to Log File
LogStream.WriteLine("Line Skipped at number: " + CurrentSourceLineNumber.ToString())
End If
Next
DestStream.Close()
LogStream.Close()
End Sub
Rewrite the project in VB.NET. Getting rid of the warnings might is only a means to get to the goal which (i presume) is a working program.
The VS 2008 method mentioned above does not work with VS 2010 and later.
for VS 2010 and later follow these steps to remove upgrade warnings...
CTRL + F
Expand the "Find..." drop-down and select "Find In Files...".
Select the "Replace in Files" tab.
Find what: [^\S\r\n]'UPGRADE_WARNING:.*\r?\n
Replace with: BLANK
Expand "Find Options".
Check "Use Regular Expressions".
Begin your search/replace/replace all.
Explained: Using regex, the [^\S\r\n] tells regex to ignore the white-space at the beginning of the line, then obviously the 'UPGRADE_WARNING: is the start of the warning comment were looking for, then the .* tells regex to ignore everything else up to the *\r?\n, then the *\r?\n tells regex to also match the line-break at the end (without this part would leave a blank line where each warning would have been).