VB How do I replace multiple characters at once? - vb.net

I am making a custom encryption application and im stuck at the replacement part.
For example I have the string "AB12AB12" and I want to encrypt it so that every A becomes a 1, every B a 2, every 1 an A and every 2 a B. If everything goes right the output should be 12AB12AB but this is what happens:
Private Sub Encrypt()
Dim str As String = "AB12AB12"
str = str.Replace("A", "1") 'now the output is "1B121B12"'
str = str.Replace("B", "2") 'now the output is "12121212"'
str = str.Replace("1", "A") 'this is where it goes wrong, output is now "A2A2A2A2"
str = str.Replace("2", "B") 'now the output is "ABABABAB" and it should be "12AB12AB"
output = str
End Sub
The problem is that with this code you keep replacing everything including the previous replacement. Maybe there is an option to like replace every character at the same time so the replacements won't get replaced...

When you use Replace to do the substitution, you get a string that has mixed characters that are processed and unprocessed, and you can't tell them apart. Process the string from start to end instead:
Private Function Encrypt(str as string) as String
Dim source As String = "AB12"
dim dest as string = "12AB"
Dim result As New StringBuilder(str.Length)
For Each c As Char In str
result.Append(dest(source.IndexOf(c)))
Next
return result.ToString()
End Function
Note: I left the name Encrypt for the method, although a substitution cipher is not what is normally considered as encryption nowadays.

The reason why this fails is because if you modify str with "A" -> "1", these '1' chars will be used when converting back as well:
"AB12AB12" --a>1--> "1B121B12"
"1B121B12" --b>2--> "12121212"
"12121212" --1>a--> "A2A2A2A2"
"A2A2A2A2" --2>b--> "ABABABAB"
Basically there are two ways to do this:
character per character
using a "temporary character"
Character-per-character
Here you fetch a character per iteration and translate it to the corresponding value:
Private Sub Encrypt()
Dim str As String = "AB12AB12"
Dim fmc As Char() = {"A","B","1","2"}
Dim toc As Char() = {"1","2","A","B"}
Dim sb As New StringBuilder(str.Length)
Dim i As Integer
For i As Integer = 1 To str.Length-1
sb.Append(fmc(Array.IndexOf(toc,GetChar(str,i))))
Next
output = sb.ToString()
End Sub
Temporary character
If you know no '3' (or another character will occur, you can simply state):
Private Sub Encrypt()
Dim str As String = "AB12AB12"
str = str.Replace("A", "3")
str = str.Replace("1", "A")
str = str.Replace("3", "1")
str = str.Replace("B", "3")
str = str.Replace("2", "B")
str = str.Replace("3", "B")
output = str
End Sub
This however will slow down the performance.
On a sidenote, as #HansPassant already pointed out, you better don't design encryption systems your own. This one for instance can trivially be solved by frequency analysis.

here i proposed a different method than you are discussed, check the possibilities
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
MsgBox(encrypt(plain_text.Text, replace_it.Text, replace_with.Text))
'display the result in the message box
End Sub
where plain_text.Text: the input text
replace_it.Text: the character to be replaced
replace_with.Text: the character is replacing.
following is the function used to perform the encryption :
Public Function encrypt(ByVal str As String, ByVal frm As String, ByVal replace As String) As String
Dim cipher As String
cipher = ""
For i As Integer = 0 To Len(str) - 1 'check each character separately
If getbyte(str, i) = frm Then
cipher = cipher & replace 'replace the character if is same as the requested
Else
cipher = cipher & getbyte(str, i)
End If
Next
Return cipher.ToString
End Function
function to get each character in the string
Private Function getbyte(ByVal s As String, ByVal place As Integer) As String
If place < Len(s) Then
place = place + 1
getbyte = Mid(s, place, 1)
Else
getbyte = ""
End If
End Function

Related

How to Replace string and loop between commas with another string

can you help me how to get Index of the same string and replace it one by one with another string?
Here my example code :
For i As Integer = 0 To 10
Dim str As String = "abcd,abcd,abcd,abcd,abcd,abcd,abcd,abcd"
Dim replace As String = "efgh"
Dim value As String
value = str.Replace("abcd", replace)
TextBox4.AppendText(value)
Next
The value will be result : efgh,efgh,efgh,efgh,efgh...
How i can create the result like this :
efgh,abcd,abcd,abcd,abcd,abcd...
for the next loop it will be like this :
abcd,efgh,abcd,abcd,abcd,abcd...
for the next loop it will be like this :
abcd,abcd,efgh,abcd,abcd,abcd...
Thank you
There are lots of ways this could be done. One perhaps inefficient way would be to split the string at the commas, replace the appropriate item in the resulting array, and then join the array back up.
Dim str As String = "abcd,abcd,abcd,abcd,abcd,abcd,abcd,abcd"
Dim replace As String = "efgh"
For i As Integer = 0 To str.Count(Function(x) x = ","c)
Dim strParts = str.Split(","c)
strParts(i) = replace
Dim value As String = String.Join(",", strParts)
Console.WriteLine(value)
Next
Output:
efgh,abcd,abcd,abcd,abcd,abcd,abcd,abcd
abcd,efgh,abcd,abcd,abcd,abcd,abcd,abcd
abcd,abcd,efgh,abcd,abcd,abcd,abcd,abcd
abcd,abcd,abcd,efgh,abcd,abcd,abcd,abcd
abcd,abcd,abcd,abcd,efgh,abcd,abcd,abcd
abcd,abcd,abcd,abcd,abcd,efgh,abcd,abcd
abcd,abcd,abcd,abcd,abcd,abcd,efgh,abcd
abcd,abcd,abcd,abcd,abcd,abcd,abcd,efgh
As #Mark mentioned there are lots of ways this could be done. One of this ways to add and remove ranges in a string is to use the StringBuilder.
Imports System.Text
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 0 To 35 Step 5
Dim sDefaultString As String = "abcd,abcd,abcd,abcd,abcd,abcd,abcd,abcd"
Dim sbText = New StringBuilder(sDefaultString)
sbText.Remove(i, 4)
sbText.Insert(i, "efgh")
TextBox1.AppendText(sbText.ToString & vbNewLine)
Next
End Sub
End Class

permutation not accepting large words

the vb.net code below permutates a given word...the problem i have is that it does not accept larger words like "photosynthesis", "Calendar", etc but accepts smaller words like "book", "land", etc ...what is missing...Pls help
Module Module1
Sub Main()
Dim strInputString As String = String.Empty
Dim lstPermutations As List(Of String)
'Loop until exit character is read
While strInputString <> "x"
Console.Write("Please enter a string or x to exit: ")
strInputString = Console.ReadLine()
If strInputString = "x" Then
Continue While
End If
'Create a new list and append all possible permutations to it.
lstPermutations = New List(Of String)
Append(strInputString, lstPermutations)
'Sort and display list+stats
lstPermutations.Sort()
For Each strPermutation As String In lstPermutations
Console.WriteLine("Permutation: " + strPermutation)
Next
Console.WriteLine("Total: " + lstPermutations.Count.ToString)
Console.WriteLine("")
End While
End Sub
Public Sub Append(ByVal pString As String, ByRef pList As List(Of String))
Dim strInsertValue As String
Dim strBase As String
Dim strComposed As String
'Add the base string to the list if it doesn't exist
If pList.Contains(pString) = False Then
pList.Add(pString)
End If
'Iterate through every possible set of characters
For intLoop As Integer = 1 To pString.Length - 1
'we need to slide and call an interative function.
For intInnerLoop As Integer = 0 To pString.Length - intLoop
'Get a base insert value, example (a,ab,abc)
strInsertValue = pString.Substring(intInnerLoop, intLoop)
'Remove the base insert value from the string eg (bcd,cd,d)
strBase = pString.Remove(intInnerLoop, intLoop)
'insert the value from the string into spot and check
For intCharLoop As Integer = 0 To strBase.Length - 1
strComposed = strBase.Insert(intCharLoop, strInsertValue)
If pList.Contains(strComposed) = False Then
pList.Add(strComposed)
'Call the same function to review any sub-permutations.
Append(strComposed, pList)
End If
Next
Next
Next
End Sub
End Module
Without actually creating a project to run this code, nor knowing how it 'doesn't accept' long words, my answer would be that there are a lot of permutations for long words and your program is just taking much longer than you're expecting to run. So you probably think it has crashed.
UPDATE:
The problem is the recursion, it's blowing up the stack. You'll have to rewrite your code to use an iteration instead of recursion. Generally explained here
http://www.refactoring.com/catalog/replaceRecursionWithIteration.html
Psuedo code here uses iteration instead of recursion
Generate list of all possible permutations of a string

Using Functions in Visual Basic

The program I'm working on has two different functions, one that calculates the number of syllables in a text file, and another that calculates the readability of the text file based on the formula
206.835-85.6*(Number of Syllables/Number of Words)-1.015*(Number of Words/Number of Sentences)
Here are the problems I'm having:
I'm supposed to display the contents of the text file in a multi-line text box.
I'm supposed to display the answer I get from the function indexCalculation in a label below the text box.
I'm having trouble calling the function to actually have the program calculate the answer to be displayed in the label.
Here is the code I have so far.
Option Strict On
Imports System.IO
Public Class Form1
Private Sub ExitToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ExitToolStripMenuItem.Click
Me.Close()
End Sub
Private Sub OpenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OpenToolStripMenuItem.Click
Dim open As New OpenFileDialog
open.Filter = "text files |project7.txt|All file |*.*"
open.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
If open.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim selectedFileName As String = System.IO.Path.GetFileName(open.FileName)
If selectedFileName.ToLower = "project7.txt" Then
Dim text As String = File.ReadAllText("Project7.txt")
Dim words = text.Split(" "c)
Dim wordCount As Integer = words.Length
Dim separators As Char() = {"."c, "!"c, "?"c, ":"c}
Dim sentences = text.Split(separators, StringSplitOptions.RemoveEmptyEntries)
Dim sentenceCount As Integer = sentences.Length
Dim vowelCount As Integer = 0
For Each word As String In words
vowelCount += CountSyllables(word)
Next
vowelCount = CountSyllables(text)
Label1.Show(indexCalculation(wordCount, sentenceCount, vowelCount))
Else
MessageBox.Show("You cannot use that file!")
End If
End If
End Sub
Function CountSyllables(word As String) As Integer
word = word.ToLower()
Dim dipthongs = {"oo", "ou", "ie", "oi", "ea", "ee", _
"eu", "ai", "ua", "ue", "au", "io"}
For Each dipthong In dipthongs
word = word.Replace(dipthong, dipthong(0))
Next
Dim vowels = "aeiou"
Dim vowelCount = 0
For Each c In word
If vowels.IndexOf(c) >= 0 Then vowelCount += 1
Next
If vowelCount = 0 Then
vowelCount = 1
End If
Return vowelCount
End Function
Function indexCalculation(ByRef wordCount As Integer, ByRef sentenceCount As Integer, ByRef vowelCount As Integer) As Integer
Dim answer As Integer = CInt(206.835 - 85.6 * (vowelCount / wordCount) - 1.015 * (wordCount / sentenceCount))
Return answer
End Function
End Class
Any suggestions would be greatly appreciated.
Here are my suggestions:
update your indexCalculation function to take in Integers, not strings. that way you don't have to convert them to numbers.
remove all of your extra variables you are not using. this will clean things up a bit.
remove your streamreader. it appears you are reading the text via File.ReadAllText
Label1.Show(answer) should be changed to Label1.Show(indexCalculation(wordCount,sentenceCount,vowelCount)) -- unless Label1 is something other than a regular label, use Label1.Text = indexCalculation(wordCount,sentenceCount,vowelCount))
Then for the vowelCount, you need to do the following:
Dim vowelCount as Integer = 0
For Each word as String in words
vowelCount += CountSyllables(word)
Next
Also, add the logic to the CountSyllables function to make it 1 if 0. If you don't want to include the last character in your vowel counting, then use a for loop instead of a for each loop and stop 1 character short.

Encrypter with Key and Message - VB.Net

Okay, so I am trying to make my program take whatever your key is, and loop through each character of the key, then find the ascii code for each character code, and then loop through each character of the message, finding the ascii code of each of them, and adding the key code to the message code, doing this for each character in the key, to each character in the message. I ran into a little problem, it changes the message right after the first letter is added, and I can't figure out how to fix it, any help would be great!
Basically, all I want is to that the ascii code for the key characters and add them to the ascii code for the message characters, then convert that final code back to the new characters in the message text. Using this:
tbxMessage.Text = (AscW(Mid(tbxMessage.Text, xForMess, 1)) + AscW(vTemp))
Here is everything I've got so far:
Public Class Form1
Function fctEncryptDecrypt(pMess As String, pKey As String) As String
If Len(tbxMessage.Text) > 0 Then
Dim xForKey As Integer
Dim xForMess As Integer
Dim intKey As Integer
Dim intMessage As Integer
Dim strAsciiKeyChar As String
Dim intAsciiKeyChar As Integer
Dim strAsciiMesChar As String
Dim intAsciiMesChar As Integer
Dim vTemp As String
Dim vTempMess As String
intKey = Len(tbxKey.Text)
intMessage = Len(tbxMessage.Text)
For xForKey = 1 To intKey
strAsciiKeyChar = Mid(tbxKey.Text, xForKey, 1)
intAsciiKeyChar = AscW(strAsciiKeyChar)
vTemp = intAsciiKeyChar
For xForMess = 1 To intMessage
strAsciiMesChar = Mid(tbxMessage.Text, xForMess, 1)
intAsciiMesChar = AscW(strAsciiMesChar)
vTempMess = vTemp + intAsciiMesChar
tbxMessage.Text = (AscW(Mid(tbxMessage.Text, xForMess, 1)) + AscW(vTemp))
Next xForMess
Next xForKey
Label1.Text = vTemp
Else
MessageBox.Show("No Message Found")
End If
End Function
Private Sub btnEncrypt_Click(sender As System.Object, e As System.EventArgs) Handles btnEncrypt.Click
fctEncryptDecrypt(tbxMessage.Text, tbxKey.Text)
End Sub
End Class
tbxMessage.Text = (AscW(Mid(tbxMessage.Text, xForMess, 1)) + AscW(vTemp))
in the inner For loop is setting the value of the text box to a number.
I'd expect the use of a temporary string variable that collects
Chr((intAsciiKeyChar + intAsciiMesChar) mod 256)
I'd also expect the key to be applied one letter at a time over the message. Something like:
Dim i as Integer
Dim s as String
Dim sKey as String
Dim sMesg as String
Dim intCharacter as Integer
s = ""
For i = 1 to len(tbxMessage.Text)
sKey = Mid(tbxKey.Text, (i mod Len(tbxKey)) + 1, 1)
sMesg = Mid(tbxMessage.Text, i, 1)
intCharacter = (WAsc(sKey) + WAsc(sMesg)) mod 256
s = s & Chr(intCharacter)
Next
tbxMessage.Text = s

What is the best way to calculate word frequency in VB.NET?

There are some good examples on how to calculate word frequencies in C#, but none of them are comprehensive and I really need one in VB.NET.
My current approach is limited to one word per frequency count. What is the best way to change this so that I can get a completely accurate word frequency listing?
wordFreq = New Hashtable()
Dim words As String() = Regex.Split(inputText, "(\W)")
For i As Integer = 0 To words.Length - 1
If words(i) <> "" Then
Dim realWord As Boolean = True
For j As Integer = 0 To words(i).Length - 1
If Char.IsLetter(words(i).Chars(j)) = False Then
realWord = False
End If
Next j
If realWord = True Then
If wordFreq.Contains(words(i).ToLower()) Then
wordFreq(words(i).ToLower()) += 1
Else
wordFreq.Add(words(i).ToLower, 1)
End If
End If
End If
Next
Me.wordCount = New SortedList
For Each de As DictionaryEntry In wordFreq
If wordCount.ContainsKey(de.Value) = False Then
wordCount.Add(de.Value, de.Key)
End If
Next
I'd prefer an actual code snippet, but generic 'oh yeah...use this and run that' would work as well.
This might be what your looking for:
Dim Words = "Hello World ))))) This is a test Hello World"
Dim CountTheWords = From str In Words.Split(" ") _
Where Char.IsLetter(str) _
Group By str Into Count()
I have just tested it and it does work
EDIT! I have added code to make sure that it counts only letters and not symbols.
FYI: I found an article on how to use LINQ and target 2.0, its a feels bit dirty but it might help someone http://weblogs.asp.net/fmarguerie/archive/2007/09/05/linq-support-on-net-2-0.aspx
Public Class CountWords
Public Function WordCount(ByVal str As String) As Dictionary(Of String, Integer)
Dim ret As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)
Dim word As String = ""
Dim add As Boolean = True
Dim ch As Char
str = str.ToLower
For index As Integer = 1 To str.Length - 1 Step index + 1
ch = str(index)
If Char.IsLetter(ch) Then
add = True
word += ch
ElseIf add And word.Length Then
If Not ret.ContainsKey(word) Then
ret(word) = 1
Else
ret(word) += 1
End If
word = ""
End If
Next
Return ret
End Function
End Class
Then for a quick demo application, create a winforms app with one multiline textbox called InputBox, one listview called OutputList and one button called CountBtn. In the list view create two columns - "Word" and "Freq." Select the "details" list type. Add an event handler for CountBtn. Then use this code:
Imports System.Windows.Forms.ListViewItem
Public Class MainForm
Private WordCounts As CountWords = New CountWords
Private Sub CountBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CountBtn.Click
OutputList.Items.Clear()
Dim ret As Dictionary(Of String, Integer) = Me.WordCounts.WordCount(InputBox.Text)
For Each item As String In ret.Keys
Dim litem As ListViewItem = New ListViewItem
litem.Text = item
Dim csitem As ListViewSubItem = New ListViewSubItem(litem, ret.Item(item).ToString())
litem.SubItems.Add(csitem)
OutputList.Items.Add(litem)
Word.Width = -1
Freq.Width = -1
Next
End Sub
End Class
You did a terrible terrible thing to make me write this in VB and I will never forgive you.
:p
Good luck!
EDIT
Fixed blank string bug and case bug
This might be helpful:
Word frequency algorithm for natural language processing
Pretty close, but \w+ is a good regex to match with (matches word characters only).
Public Function CountWords(ByVal inputText as String) As Dictionary(Of String, Integer)
Dim frequency As New Dictionary(Of String, Integer)
For Each wordMatch as Match in Regex.Match(inputText, "\w+")
If frequency.ContainsKey(wordMatch.Value.ToLower()) Then
frequency(wordMatch.Value.ToLower()) += 1
Else
frequency.Add(wordMatch.Value.ToLower(), 1)
End If
Next
Return frequency
End Function