I am trying to create custom convert cyrillic to latin text function in VB.net. I've never tried to make a custom function so I don't know what I am doing wrong. I have one problem and also, function doesn't work : Object reference not set to an instance of an object.
Public Function ConvertCtoL(ByVal ctol As String) As String
ctol = Replace(ctol, "Б", "B")
ctol = Replace(ctol, "б", "b")
**End Function** ' doesn't return a value on all code paths
Since I didn't found a solution for cyrillic to latin text I was planning to create function that would replace every letter from one alphabet to another.
You need Return ctol to tell it what value to return.
Perhaps researching "lookup table" would help you make a neater function.
Edit: The Wikipedia entry for Lookup table should be a good start.
Here is a simple example:
Imports System.Text
Module Module1
Function ReverseAlphabet(s As String) As String
Dim inputTable() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
Dim outputTable() As Char = "ZYXWVUTSRQPONMLKJIHGFEDBCA".ToCharArray()
Dim sb As New StringBuilder
For Each c As Char In s
Dim inputIndex = Array.IndexOf(inputTable, c)
If inputIndex >= 0 Then
' we found it - look up the value to convert it to.
Dim outputChar = outputTable(inputIndex)
sb.Append(outputChar)
Else
' we don't know what to do with it, so leave it as is.
sb.Append(c)
End If
Next
Return sb.ToString()
End Function
Sub Main()
Console.WriteLine(ReverseAlphabet("ABC4")) ' outputs "ZYX4"
Console.ReadLine()
End Sub
End Module
Related
I would like to ask for your help regarding my problem. I want to create a module for my program where it would read .txt file, find a specific value and insert it to the text box.
As an example I have a text file called system.txt which contains single line text. The text is something like this:
[Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]
What i want to do is to get only the last name value "xxx_xxx" which every time can be different and insert it to my form's text box
Im totally new in programming, was looking for the other examples but couldnt find anything what would fit exactly to my situation.
Here is what i could write so far but i dont have any idea if there is any logic in my code:
Dim field As New List(Of String)
Private Sub readcrnFile()
For Each line In File.ReadAllLines(C:\test\test_1\db\update\network\system.txt)
For i = 1 To 3
If line.Contains("Last Name=" & i) Then
field.Add(line.Substring(line.IndexOf("=") + 2))
End If
Next
Next
End Sub
Im
You can get this down to a function with a single line of code:
Private Function readcrnFile(fileName As String) As IEnumerable(Of String)
Return File.ReadLines(fileName).Where(Function(line) RegEx.IsMatch(line, "[[[]Last Name=(?<LastName>[^]]+)]").Select(Function(line) RegEx.Match(line, exp).Groups("LastName").Value)
End Function
But for readability/maintainability and to avoid repeating the expression evaluation on each line I'd spread it out a bit:
Private Function readcrnFile(fileName As String) As IEnumerable(Of String)
Dim exp As New RegEx("[[[]Last Name=(?<LastName>[^]]+)]")
Return File.ReadLines(fileName).
Select(Function(line) exp.Match(line)).
Where(Function(m) m.Success).
Select(Function(m) m.Groups("LastName").Value)
End Function
See a simple example of the expression here:
https://dotnetfiddle.net/gJf3su
Dim strval As String = " [Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]"
Dim strline() As String = strval.Split(New String() {"[", "]"}, StringSplitOptions.RemoveEmptyEntries) _
.Where(Function(s) Not String.IsNullOrWhiteSpace(s)) _
.ToArray()
Dim lastnameArray() = strline(1).Split("=")
Dim lastname = lastnameArray(1).ToString()
Using your sample data...
I read the file and trim off the first and last bracket symbol. The small c following the the 2 strings tell the compiler that this is a Char. The braces enclosed an array of Char which is what the Trim method expects.
Next we split the file text into an array of strings with the .Split method. We need to use the overload that accepts a String. Although the docs show Split(String, StringSplitOptions), I could only get it to work with a string array with a single element. Split(String(), StringSplitOptions)
Then I looped through the string array called splits, checking for and element that starts with "Last Name=". As soon as we find it we return a substring that starts at position 10 (starts at zero).
If no match is found, an empty string is returned.
Private Function readcrnFile() As String
Dim LineInput = File.ReadAllText("system.txt").Trim({"["c, "]"c})
Dim splits = LineInput.Split({"]["}, StringSplitOptions.None)
For Each s In splits
If s.StartsWith("Last Name=") Then
Return s.Substring(10)
End If
Next
Return ""
End Function
Usage...
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = readcrnFile()
End Sub
You can easily split that line in an array of strings using as separators the [ and ] brackets and removing any empty string from the result.
Dim input As String = "[Name=John][Last Name=xxx_xxx][Address=xxxx][Age=22][Phone Number=8454845]"
Dim parts = input.Split(New Char() {"["c, "]"c}, StringSplitOptions.RemoveEmptyEntries)
At this point you have an array of strings and you can loop over it to find the entry that starts with the last name key, when you find it you can split at the = character and get the second element of the array
For Each p As String In parts
If p.StartsWith("Last Name") Then
Dim data = p.Split("="c)
field.Add(data(1))
Exit For
End If
Next
Of course, if you are sure that the second entry in each line is the Last Name entry then you can remove the loop and go directly for the entry
Dim data = parts(1).Split("="c)
A more sophisticated way to remove the for each loop with a single line is using some of the IEnumerable extensions available in the Linq namespace.
So, for example, the loop above could be replaced with
field.Add((parts.FirstOrDefault(Function(x) x.StartsWith("Last Name"))).Split("="c)(1))
As you can see, it is a lot more obscure and probably not a good way to do it anyway because there is no check on the eventuality that if the Last Name key is missing in the input string
You should first know the difference between ReadAllLines() and ReadLines().
Then, here's an example using only two simple string manipulation functions, String.IndexOf() and String.Substring():
Sub Main(args As String())
Dim entryMarker As String = "[Last Name="
Dim closingMarker As String = "]"
Dim FileName As String = "C:\test\test_1\db\update\network\system.txt"
Dim value As String = readcrnFile(entryMarker, closingMarker, FileName)
If Not IsNothing(value) Then
Console.WriteLine("value = " & value)
Else
Console.WriteLine("Entry not found")
End If
Console.Write("Press Enter to Quit...")
Console.ReadKey()
End Sub
Private Function readcrnFile(ByVal entry As String, ByVal closingMarker As String, ByVal fileName As String) As String
Dim entryIndex As Integer
Dim closingIndex As Integer
For Each line In File.ReadLines(fileName)
entryIndex = line.IndexOf(entry) ' see if the marker is in our line
If entryIndex <> -1 Then
closingIndex = line.IndexOf(closingMarker, entryIndex + entry.Length) ' find first "]" AFTER our entry marker
If closingIndex <> -1 Then
' calculate the starting position and length of the value after the entry marker
Dim startAt As Integer = entryIndex + entry.Length
Dim length As Integer = closingIndex - startAt
Return line.Substring(startAt, length)
End If
End If
Next
Return Nothing
End Function
In my class today I was told change some of my sub-procedures to functions, and when I asked why it's better my teacher struggled to answer, generally, i've always thought that functions should only really be used when a value is returned. In the two examples below; is there one method that should be used over the other, or does it not matter? And if it does matter why?
Thanks in advance.
Method 1 (Sub-Proc):
Sub EncryptString(ByVal unkString, ByRef encryptedString)
For i = 1 To Len(unkString)
encryptedString += "*"
Next
End Sub
Method 2 (Function):
[In main I assign the variable "encryptedString" to this function].
Function encryptString(ByVal unkString) As String
For i = 1 To Len(unkString)
encryptString += "*"
Next
End Function
You've misunderstood what they're trying to tell you. In your Function example there is no difference. What your teacher is expecting is like this:
Function EncryptString(ByVal unkString) As String
Dim encryptedString As String = ""
For i = 1 To Len(unkString)
encryptedString += "*"
Next
Return encryptedString
End Function
This is a cleaner and more reusable way than modifying a field, an argument passed ByRef, or the underlying variable of the function
Your example show one of the multiple reason, who initialize the data is unclear. With your sample code, the first option would append to the passed string while the second would create a new string.
The first method would have to specify if it needs an empty string or explain why it appends. While the second method clearly show that a new string will be returned.
Sub Main()
Dim u, e As String
u = "123"
e = "123"
EncryptString1(u, e)
Console.WriteLine(e) ' Display: 123***
u = "123"
e = "123"
e = encryptString2(u)
Console.WriteLine(e) ' Display: ***
Console.ReadLine()
End Sub
Sub EncryptString1(ByVal unkString As String, ByRef encryptedString As String)
For i As Integer = 1 To Len(unkString)
encryptedString += "*"
Next
End Sub
Function encryptString2(ByVal unkString As String) As String
encryptString2 = ""
For i As Integer = 1 To Len(unkString)
encryptString2 += "*"
Next
End Function
Please have option strict on. Also, personally, I rather create a variable instead of using the function name, use .Length instead of Len() and concatenate with & instead of +.
Function encryptString3(ByVal unkString As String) As String
Dim encryptedString As String = ""
For i As Integer = 1 To unkString.Length
encryptedString &= "*"
Next
Return encryptedString
End Function
Or just use the New operator of the String class.
Dim encryptedString as New String("*"c, unkString.Length)
Well, when I was learning this stuff, it was always to use functions to calculate values and subs to do other stuff. I guess for something very general, it doesn't really matter which methodology you use, as you have illustrated in your example. See the link below for further discussion on this topic.
http://analystcave.com/vba-function-vs-vba-sub-procedures/
I am familiar with this post: How to Return a result from a VBA Function but changing my code does not seem to help.
I want to write a simple function in VBA that allows to lowercase an input sentence. I wrote this:
Private Function Converter(inputText As String) As String
Converter = LCase(inputText)
End Function
Sub test()
Dim new_output As String
new_output = Converter("Henk")
MsgBox (new_output)
End Sub
I tried following the advice I found at another stackoverflow post. I made me change this:
Private Function Converter(inputText As String)
Set outputText = LCase(inputText)
End Function
Sub test()
Dim new_output As String
Set new_output = Converter("Henk")
MsgBox (new_output)
End Sub
However, now I get an error that an object is required. Why does it require an object now? I dont get it...
Set outputText = LCase(inputText)
The Set keyword is reserved for Object data types. Unlike VB.NET, String in VBA is a basic data types.
So you dont Set a variable to a string. Drop the second version of your code altogether. It doesn't make sense. That "advice" was probably in another context.
To fix your first version
1- Assign the returned result to the name of the function Converter
2- It would be beneficial to specify explicitly the return type, as String. Currently it is a Variant that always embeds a String, so better make it explicit:
' vvvvvvvvv
Private Function Converter(inputText As String) As String
Converter = LCase(inputText) ' <------------ assign return to name of function
End Function
Hi I need to change WordCount and CountVowel procedures to functions and create a function to count number of consonants in a string.
I have done these two procedures but I cannot figure out how to do the last part. I am fairly new to programming.
My current code is given below:
Sub Main()
Dim Sentence As String
Console.WriteLine("Sentence Analysis" + vbNewLine + "")
Console.WriteLine("Enter a sentence, then press 'Enter'" + vbNewLine + "")
Sentence = Console.ReadLine()
Console.WriteLine("")
Call WordCount(Sentence)
Call VowelCount(Sentence)
Console.ReadLine()
End Sub
Sub WordCount(ByVal UserInput As String)
Dim Space As String() = UserInput.Split(" ")
Console.WriteLine("There are {0} words", Space.Length)
End Sub
Sub VowelCount(ByVal UserInput As String)
Dim i As Integer
Dim VowelNumber As Integer
Dim Vowels As String = "aeiou"
For i = 1 To Len(UserInput)
If InStr(Vowels, Mid(UserInput, i, 1)) Then
VowelNumber = VowelNumber + 1
End If
Next
Console.WriteLine("There are {0} vowels", VowelNumber)
End Sub
Thanks for your time
I would use the following three functions. Note that WordCount uses RemoveEmptyEntries avoids counting empty words when there are multiple spaces between words.
The other two functions count upper case vowels as vowels, rather than just lower case. They take advantage of the fact that strings can be treated as arrays of Char, and use the Count method to count how many of those Chars meet certain criteria.
Note that the designation of "AEIOU" as vowels may not be correct in all languages, and even in English "Y" is sometimes considered a vowel. You might also need to consider the possibility of accented letters such as "É".
Function WordCount(UserInput As String) As Integer
Return UserInput.Split({" "c}, StringSplitOptions.RemoveEmptyEntries).Length
End Function
Function VowelCount(UserInput As String) As Integer
Return UserInput.Count(Function(c) "aeiouAEIOU".Contains(c))
End Function
Function ConsonantCount(UserInput As String) As Integer
Return UserInput.Count(Function(c) Char.IsLetter(c) And Not "aeiouAEIOU".Contains(c))
End Function
To turn each of your Sub routines into a Function, you need to do three things. First, you need to change the Sub and End Sub keywords to Function and End Function, respectively. So:
Sub MyMethod(input As String)
' ...
End Sub
Becomes:
Function MyMethod(input As String)
' ...
End Function
Next, since it's a function, it needs to return a value, so your Function declaration needs to specify the type of the return value. So, the above example would become:
Function MyMethod(input As String) As Integer
' ...
End Function
Finally, the code in the function must actually specify what the return value will be. In VB.NET, that is accomplished by using the Return keyword, like this:
Function MyMethod(input As String) As Integer
Dim result As Integer
' ...
Return result
End Function
So, to apply that to your example:
Sub WordCount(ByVal UserInput As String)
Dim Space As String() = UserInput.Split(" ")
Console.WriteLine("There are {0} words", Space.Length)
End Sub
Would become:
Function WordCount(userInput As String) As Integer
Dim Space As String() = UserInput.Split(" ")
Return Space.Length
End Sub
Note, ByVal is the default, so you don't need to specify it, and parameter variables, by standard convention in .NET are supposed to be camelCase rather than PascalCase. Then, when you call the method, you can use the return value of the function like this:
Dim count As Integer = WordCount(Sentence)
Console.WriteLine("There are {0} words", count)
As far as counting consonants goes, that will be very similar to your VowelCount method, except that you would give it the list of consonants to look for instead of vowels.
You could use the Regex class. It's designed to search for substrings using patterns, and it's rather fast at it too.
Sub VowelCount(ByVal UserInput As String)
Console.WriteLine("There are {0} vowels", System.Text.RegularExpressions.Regex.Matches(UserInput, "[aeiou]", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Count.ToString())
End Sub
[aeiou] is the pattern used when performing the search. It matches any of the characters you've written inside the brackets.
Example:
http://ideone.com/LEYC30
Read more about Regex:
MSDN - .NET Framework Regular Expressions
MSDN - Regular Expression Language - Quick Reference
VB is no longer a language I use frequently but I don't think I'm going to steer you wrong even without testing this out.
Sub Main()
Dim Sentence As String
Console.WriteLine("Sentence Analysis" + vbNewLine + "")
Console.WriteLine("Enter a sentence, then press 'Enter'" + vbNewLine + "")
Sentence = Console.ReadLine()
Console.WriteLine("")
'usually it's better just let the function calculate a value and do output elsewhere
'so I've commented your original calls so you can see where they used to be
'Call WordCount(Sentence)
Console.WriteLine("There are {0} words", WordCount(Sentence))
'Call VowelCount(Sentence)
Console.WriteLine("There are {0} vowels", VowelCount(Sentence))
Console.ReadLine()
End Sub
Function WordCount(ByVal UserInput As String) As Integer
Dim Space As String() = UserInput.Split(" ")
WordCount = Space.Length
'or just shorten it to one line...
'Return UserInput.Split(" ").Length
End Function
Function VowelCount(ByVal UserInput As String) As Integer
Dim i As Integer
Dim VowelNumber As Integer
Dim Vowels As String = "aeiou"
For i = 1 To Len(UserInput)
If InStr(Vowels, Mid(UserInput, i, 1)) Then
VowelNumber = VowelNumber + 1
End If
Next
VowelCount = VowelNumber
End Function
The most obvious change between a sub and a function is changing the keywords that wrap up the procedure. For this conversation let's just say that's one good word to use for encompassing both concepts since they're very similar and many languages don't really draw such a big distinction.
For Visual Basic's purposes a function needs to return something and that's indicated by the As Integer that I added to the end of both of the function declarations (can't remember if that's the right VB terminology.) Also in VB you return a value to the caller by assigning to the name of the function (also see edit below.) So I replaced those lines that were WriteLines with appropriate assignments. Last I moved those WriteLine statements up into Main. The arguments needed to be changed to use the function return values rather than the variables they originally referenced.
Hopefully I'm not doing your homework for you!
EDIT: Visual Basic underwent a lot of changes to the language during the move to .Net back in the early 2000's. I had forgotten (or possibly not even realized) that the new preferred choice for returning a value is now more in line with languages like C#. So rather than assigning values to WordCount and VowelCount you can just use Return. One difference between the two is that a Return will cause the sub/function to exit at that point even if there is other code afterward. This might be useful inside an if...end if for example. I'm hoping this helps you learn something rather than just being confusing.
EDIT #2: Now that I see the accepted answer and re-read the question it seems there was a small part about counting consonants that got overlooked. At this point I assume this was indeed a classroom exercise and the intended answer was possibly even to derive the consonant count by using the other functions.
Here you go.
Function WordCount(ByVal UserInput As String) As Integer
Dim Space As String() = UserInput.Split(" ")
Return Space.Length
End Function
Function VowelCount(ByVal UserInput As String) As Integer
Dim i As Integer
Dim VowelNumber As Integer
Dim Vowels As String = "aeiou"
For i = 1 To Len(UserInput)
If InStr(Vowels, Mid(UserInput, i, 1)) Then
VowelNumber = VowelNumber + 1
End If
Next
Return VowelNumber
End Function
Function ConsonantCount(ByVal UserInput As String) As Integer
Dim i As Integer
Dim ConsonantNumber As Integer
Dim Consonants As String = "bcdfghjklmnpqrstvwxyz"
For i = 1 To Len(UserInput)
If InStr(Consonants, Mid(UserInput, i, 1)) Then
ConsonantNumber = ConsonantNumber + 1
End If
Next
Return ConsonantNumber
End Function
I have looked on the web and I cannot find anything that helps me, all I can find is changing the characters into ASCII or Hexadecimal. However I would like to do it a different way. For example, say the string that got passed in was abcdef, I would like to have a key which changes these characters into another string such as qwpolz. Is there an easier way than declaring each character in the alphabet to be another character like:
Dim sText As String = "Hello"
Dim sEncode As String = ""
Dim iLength As Integer
Dim i As Integer
iLength = Len(sText)
For i = 1 To iLength
sEncode = sEncode ????
Next
Return sEncode
And then have a very lengthy loop which checks for these loops? There must be a much simpler way. Can anybody help by pointing me in the right direction?
Edit: Why downvote? Seriously, it's a legitimate question. Instead of downvoting for no reason, just move onto another question.
Well actually, this sounds like a Caesar sipher
Private Overloads Shared Function Encrypt(ByVal ch As Char, ByVal code As Integer) As Char
If Not Char.IsLetter(ch) Then
Return ch
End If
Dim offset As Char = IIf(Char.IsUpper(ch), "A", "a")
Return CType((((ch + (code - offset)) Mod 26) + offset),Char)
End Function
Private Overloads Shared Function Encrypt(ByVal input As String, ByVal code As Integer) As String
Return New String(input.ToCharArray.Select(() => { }, Encrypt(ch, code)).ToArray)
End Function
Private Shared Function Decrypt(ByVal input As String, ByVal code As Integer) As String
Return Encrypt(input, (26 - code))
End Function
Note that this assumes, that you use English alphabet. In general case where for example you have 'ä', 'ö', 'š', 'ž', 'ß', 'õ', 'ü' etc. this would not work. In that case it is simpler to just create a list/dictionary of your ordered alphabet and use it.
Example use:
encrypted = Encrypt(sText, 5)
decypted = Decrypt(encrypted, 5)
Sounds as if you want to modify a string by replacing each character with a different character according to a mapping table. An efficient approach is to use a Dictionary(Of Char, Char). But easier to write and maintain is something like this:
Shared ReadOnly replaceChars As String = "abcdef"
Shared ReadOnly withChars As String = "qwpolz"
Public Shared Function ReplaceAll(input As String) As String
Dim newChars = From c In input
Let index = replaceChars.IndexOf(c)
Select If(index >= 0, withChars(index), c)
Return String.Concat(newChars)
End Function
So the first string contains the chars that you want to replace and the second the replacement characters. Both strings must have the same length.
If you want to support case insensitivity:
Public Shared Function ReplaceAll(input As String, comparison As StringComparison) As String
Dim newChars = From c In input
Let index = replaceChars.IndexOf(c.ToString(), comparison)
Select If(index >= 0, withChars(index), c)
Return String.Concat(newChars)
End Function
Note that this is also a loop. There is no way to avoid some kind of loops if you want to replace multiple characters or strings.