Flesch Readability Index in Visual Basic - vb.net

I'm working on a program that is supposed to perform the calculations for the Flesch Readability Index. The program is supposed to read in a text file "Project7.txt", it's then supposed to display the text in a multi-line text box and perform the following calculations:
Count the number of words in the file.
Count the number of syllables in the file.
Count the number of sentences in the file (a sentence can be ended by a ".", "?", "!", or ":"
The program is then supposed to plug the values into the following formula and display the result in a label (label1).
206.835-85.6*(Number of syllables/Number of words) - 1.015*(Number of words/Number of sentences)
Here is the code I have written 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 doc As String = ""
Dim line As String
Using reader As New StreamReader(open.OpenFile)
While Not reader.EndOfStream
doc += reader.ReadLine
Console.WriteLine(line)
End While
Dim text = File.ReadAllText("Project7.txt")
Dim words = text.Split(" "c)
Dim wordCount = words.Length
Dim separators As Char() = {"."c, "!"c, "?"c, ":"c}
Dim sentences = text.Split(separators, StringSplitOptions.RemoveEmptyEntries)
Dim sentenceCount = sentences.Length
End Using
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
Return vowelCount
End Function
End Class
Any suggestions are appreciated. Thanks in advance for the help.

Is the code always reporting one more sentence than there actually is?
If so take a look at this from the String.Split method MSDN docs:
When the Split function encounters two delimiters in a row, or a
delimiter at the beginning or end of the string, it interprets them as
surrounding an empty string ("")...
I'm sure your last sentence ends with your sentence delimiter so what's happening is your assignment to sentences is getting an extra, empty array element. See for yourself by breakpointing the line after your assignment and hovering your mouse over sentences. Examine the contents of the array.
The fix is to call Split with the option to remove empty array values. To do that though you'll need to call the Split overload that takes an array of Char for the delimiters:
Replace this line:
Dim sentences = text.Split("."c, "!"c, "?"c, ":"c)
With this:
Dim separators As Char() = {"."c, "!"c, "?"c, ":"c}
Dim sentences = text.Split(separators, StringSplitOptions.RemoveEmptyEntries)
And you should be good.

Related

exclude header from csv in vb.net

I got a .csv and I want to load it into a datagridview. I have a button called button1 and I got a datagridview called datagridview1. I click the button and it appears... including the header, which I don't want.
Please:
How do I exclude the header from the .csv ?
code:
Imports System.IO
Imports System.Text
Public Class CSV_Reader
Private Sub CSV_Reader_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim filename As String = "C:\Users\Gaius\Desktop\meepmoop.csv"
Dim thereader As New StreamReader(filename, Encoding.Default)
Dim colsexpected As Integer = 7
Dim sline As String = ""
DataGridView1.Rows.Clear()
Do
sline = thereader.ReadLine
If sline Is Nothing Then Exit Do
Dim words() As String = sline.Split(";")
DataGridView1.Rows.Add("")
If words.Length = colsexpected Then
For ix As Integer = 0 To 6
DataGridView1.Rows(DataGridView1.Rows.Count - 2).Cells(ix).Value = words(ix)
Next
Else
DataGridView1.Rows(DataGridView1.Rows.Count - 2).Cells(0).Value = "ERROR"
End If
Loop
thereader.Close()
End Sub
End Class
meepmoop.csv:
alpha;bravo;charlie;delta;echo;foxtrot;golf
1;meep;moop;meep;moop;meep;moop
2;moop;meep;moop;meep;moop;meep
3;meep;moop;meep;moop;meep;moop
4;moop;meep;moop;meep;moop;meep
5;meep;moop;meep;moop;meep;moop
6;moop;meep;moop;meep;moop;meep
7;meep;moop;meep;moop;meep;moop
8;moop;meep;moop;meep;moop;meep
9;meep;moop;meep;moop;meep;moop
10;moop;meep;moop;meep;moop;meep
edit:
[...]
Dim sline As String = ""
DataGridView1.Rows.Clear()
Dim line As String = thereader.ReadLine()
If line Is Nothing Then Return
Do
sline = thereader.ReadLine
[...]
The above addition to the code works but I have no idea why. Nor do I understand why I have to -2 rather than -1. I can't rely on guesswork, I'm expected to one day do this professionally. But I just can't wrap my head around it. Explanation welcome.
edit:
Do
sline = thereader.ReadLine
If sline Is Nothing Then Exit Do
Dim words() As String = sline.Split(";")
If words.Count = 7 Then
DataGridView1.Rows.Add(words(0), words(1), words(2), words(3), words(4), words(5), words(6))
Else
MsgBox("ERROR - There are " & words.Count & " columns in this row and there must be 7!")
End If
Loop
I've shortened the Loop on the advice of a coworker, taking his word on it being 'better this way'.
Another method, using Enumerable.Select() + .Skip()
As noted in Ondřej answer, there's a specific tool for these operations: TextFieldParser
But, if there are no special requirements and the string parsing is straightforward enough, it can be done with the standard tools, as shown in Tim Schmelter answer.
This method enumerates the string arrays returned by the Split() method, and groups them in a list that can be then used in different ways. As a raw text source (as in this case) or as a DataSource.
Dim FileName As String = "C:\Users\Gaius\Desktop\meepmoop.csv"
Dim Delimiter As Char = ";"c
Dim ColsExpected As Integer = 7
If Not File.Exists(FileName) Then Return
Dim Lines As String() = File.ReadAllLines(FileName, Encoding.Default)
Dim StringColumns As List(Of String()) =
Lines.Select(Function(line) Split(line, Delimiter, ColsExpected, CompareMethod.Text)).
Skip(1).ToList()
DataGridView1.Rows.Clear()
'If the DataGridView is empty, add a `[ColsExpected]` number of `Columns`:
DataGridView1.Columns.AddRange(Enumerable.Range(0, ColsExpected).
Select(Function(col) New DataGridViewTextBoxColumn()).ToArray())
StringColumns.Select(Function(row) DataGridView1.Rows.Add(row)).ToList()
If you instead want to include and use the Header because your DataGridView is empty (it has no predefined Columns), you could use the Header line in the .csv file to create the control's Columns:
'Include the header (no .Skip())
Dim StringColumns As List(Of String()) =
Lines.Select(Function(line) Split(line, Delimiter, ColsExpected, CompareMethod.Text)).ToList()
'Insert the columns with the .csv header columns description
DataGridView1.Columns.AddRange(Enumerable.Range(0, ColsExpected).
Select(Function(col, idx) New DataGridViewTextBoxColumn() With {
.HeaderText = StringColumns(0)(idx)
}).ToArray())
'Remove the header line...
StringColumns.RemoveAt(0)
StringColumns.Select(Function(row) DataGridView1.Rows.Add(row)).ToList()
You can skip the header by calling ReadLine twice. Also use the Using-statement:
Using thereader As New StreamReader(filename, Encoding.Default)
Dim colsexpected As Integer = 7
Dim sline As String = ""
Dim line As String = thereader.ReadLine() ' header
if line is Nothing Then Return
Do
sline = thereader.ReadLine()
If sline Is Nothing Then Exit Do
Dim words() As String = sline.Split(";"c)
' ... '
Loop
End Using
You should use VB.NET class that is designed and tested for this purpose. It is Microsoft.VisualBasic.FileIO.TextFieldParser and you can skip header by calling ReadFields() once before you start parsing in loop.

English sentence as input and translates it into Textese

working on a project where I input a text file and write a sentence in an "English" text box and with a click of a button the program translates it into "textese" type of language. It will only change words listed in the text file and ignore everything else. Below is the code I have, and wondering what is going wrong, it fails to run and highlights my If Then statement, so I think my issue is there but not sure what. A few examples of what is in the text file and how they are ordered / separated by a comma.
anyone,ne1
are,r
ate,8
band,b&
be,b
before,b4
busy,bz
computer,puter
Public Class frmTextese
Private Sub btnTranslate_Click(sender As Object, e As EventArgs) Handles btnTranslate.Click
Dim inputData() As String = IO.File.ReadAllLines("Textese.txt")
Dim english As Integer = 0
Dim englishSentence As String = txtEnglish.Text
Dim result() As String = englishSentence.Split(" "c)
Do While english < (result.Length - 1)
Dim line As String
Dim data() As String
Dim englishArray As String
Dim texteseArray As String
For i As Integer = 0 To (inputData.Length - 1)
line = inputData(i)
data = line.Split(","c)
englishArray = line.Split(","c)(0)
texteseArray = line.Split(","c)(1)
If result(i).StartsWith(englishArray(i)) Then
If englishArray(i).Equals(texteseArray(i)) Then
result(i) = texteseArray(i)
End If
End If
txtTextese.Text = result(i)
Next
Loop
End Sub
End Class
You only need to compare result(i) against englishArray. Also, your while loop was an endless loop. When searching the textese array, once you find a match, you can quit searching and go on to the next english word. Finally, you should take care to use variable names that describe their purpose.
Look at this code (untested). I made the string comparison case insensitive, but that is not required.
Private Sub btnTranslate_Click(sender As Object, e As EventArgs) Handles btnTranslate.Click
'Get all the textese definitions
Dim inputData() As String = IO.File.ReadAllLines("Textese.txt")
Dim english As Integer = 0
Dim englishSentence As String = txtEnglish.Text
Dim result() As String = englishSentence.Split(" "c)
Do While english < (result.Length - 1)
Dim line As String
Dim data() As String
Dim englishArray As String
Dim texteseArray As String
For i As Integer = 0 To (inputData.Length - 1)
'Split the textese entry into two parts
line = inputData(i)
data = line.Split(","c)
englishArray = data(0)
texteseArray = data(1)
'Compare the word in the english sentence against the word in the textese array
'using a case insensitive comparison (not required)
If result(i).Equals(englishArray, StringComparison.CurrentCultureIgnoreCase) Then
'Replace the word in the sentence with its textese version
result(i) = texteseArray
'If we found the word, there is no need to continue searching, so
'skip to the next word in the english sentence
Exit For
End If
Next
'Increment the loop counter to avoid an endless loop
english = english + 1
Loop
'Take the elements of the result array and join them together, separated by spaces
txtTextese.Text = String.Join(" ", result)
End Sub

Creating a text translator with text file

I'm trying to have this program take a normal English sentence in one text box and with the click of a button convert it into a textese sentence.
Any word that can be shortened will be replaced with the words in a text file.
An example of a line in the text file is
anyone,ne1
There are 52 lines (replacement words).
What would be the best way to approach this problem? Is a nested loop possibly a good route to take?
I don't have much experience and trying to learn the language more so open to trying all methods.
Below is what I have so far before I begin the coding process as I'm not really sure where to head from here. Only the words that are found within the text file will be replaced, so I think I'd use an If/Else statement that would ignore and leave any words not found alone.
Public Class frmTextese
Dim inputData() As String = IO.File.ReadAllLines("Textese.txt")
Private Sub btnTranslate_Click(sender As Object, e As EventArgs) Handles btnTranslate.Click
Dim english As Integer = 0
Dim englishSentence As String = txtEnglish.Text
Dim result() As String
result = englishSentence.Split(englishSentence)
Dim line As String
Dim data() As String
For i As Integer = 0 To (inputData.Length - 1)
line = inputData(i)
data = line.Split(" "c)
Next
'txtTextese.Text =
End Sub
End Class
An image of what I am trying to achieve:
Try this and have a look at the comments to get an idea of what is happening. I should add that strictly speaking, this site isn't a code writing service, but I can't help it sometimes. This also takes into account capitalization of words and common punctuation after the words. It's a bit quick and dirty, but for the basics, it seems to work ok.
Public Class frmTextese
'create a new empty dictionary where we'll add the pairs of english and
'textese words
Dim englishToTextese As New Dictionary(Of String, String)
Private Sub frmTextese_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'load textese dictionary to an array
Dim filedata() As String = IO.File.ReadAllLines("k:\textese.txt")
'Split each line into its elements and add to the dictionary
For Each item As String In filedata
Dim splitstring() As String = item.Split(","c)
englishToTextese.Add(splitstring(0), splitstring(1))
Next
End Sub
Private Function IsCapitalized(word As String) As Boolean
'If the first character in the word is upper case then return true
'else return false
If Mid(word, 1, 1) = Mid(word, 1, 1).ToUpper Then
Return True
Else
Return False
End If
End Function
Private Function GetPunctuation(word As String) As Tuple(Of String, String)
'If the last character in the word is a punctuation mark, return a pair of values which are :
'the word without puctuation, and the punctuation. Else
'return the word and an empty string
Dim result As Tuple(Of String, String)
If "!':;?/.,".Contains(word.Last()) Then
result = New Tuple(Of String, String)(Mid(word, 1, word.Length - 1), word.Last)
Else
result = New Tuple(Of String, String)(word, "")
End If
Return result
End Function
Private Sub btnTranslate_Click(sender As Object, e As EventArgs) Handles btnTranslate.Click
Dim textese As String = ""
'split the text in the txtEnglish textbox into its component words including any punctuation
Dim words() As String = txtEnglish.Text.Split(" "c)
For Each englishWord As String In words
'get the word and any punctuation following it as a pair of items
'and store in punctResult
Dim punctResult As Tuple(Of String, String) = GetPunctuation(englishWord)
Dim texteseWord As String
'store the first item (the word) in englishWord
englishWord = punctResult.Item1
'store the secont item (the punctuation or a blank string) in punctuation
Dim punctuation As String = punctResult.Item2
'If the english word is in the dictionary
If englishToTextese.ContainsKey(englishWord.ToLower) Then
'get the textesevertion
texteseWord = englishToTextese(englishWord.ToLower)
'if the original english word was capiutalized, capitalize the textese word
If IsCapitalized(englishWord) Then
texteseWord = texteseWord.ToUpperInvariant
End If
'add the word to the textese sentence
textese = textese & texteseWord & punctuation & " "
Else
'if the word isn't in the dictionary, add the original english word and its original state
'of capitalization and punctuation to the textese sentence
textese = textese & englishWord & punctuation & " "
End If
Next
'store the new texteze sentence in the textbox
txtTextese.Text = textese
End Sub
End Class

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.

how to extract certain text from string

How do I filter/extract strings?
I have converted a PDF file into String using itextsharp and I have the text displayed into a Richtextbox1.
However there are too many irrelevant text that I don't need in the Richtextbox.
Is there a way I can display the text I want based on keywords, the entire length of the text.
Example of text that is displayed in textrichbox1 after conversation of PDF to text:
**774**
**Bos00232940
Bos00320491
Das1234
Das3216**
RAGE*
So the keywords would be "Bos", "Das", "774". and the new text that would be displayed in the richtextbox1 is shown below, instead of the entire text above.
*Bos00232940
Bos00320491
Das1234
Das3216
774*
Here is what I have so far. But it doesn't work it still displays the entire PDF in the richtextbox.
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim pdffilename As String
pdffilename = TextBox1.Text
Dim filepath = "c:\temp\" & TextBox1.Text & ".pdf"
Dim thetext As String
thetext = GetTextFromPDF(filepath)
Dim lines() As String = System.Text.RegularExpressions.Regex.Split(thetext, Environment.NewLine)
Dim keywords As New List(Of String)
keywords.Add("Bos")
keywords.Add("Das")
keywords.Add("774")
Dim newTextLines As New List(Of String)
For Each line As String In lines
For Each keyw As String In thetext
If line.Contains(keyw) Then
newTextLines.Add(line)
Exit For
End If
Next
Next
RichTextBox1.Text = String.Join(Environment.NewLine, newTextLines.ToArray)
End Sub
SOLUTION
Thanks everyone for your help. Below is the code that worked and did exactly what I wanted it to do.
Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim pdffilename As String
pdffilename = TextBox1.Text
Dim filepath = "c:\temp\" & TextBox1.Text & ".pdf"
Dim thetext As String
thetext = GetTextFromPDF(filepath)
Dim re As New Regex("[\t ](?<w>((774)|(Bos)|(Das))[a-z0-9]*)[\t ]", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
Dim Lines() As String = {thetext}
Dim words As New List(Of String)
For Each s As String In Lines
Dim mc As MatchCollection = re.Matches(s)
For Each m As Match In mc
words.Add(m.Groups("w").Value)
Next
Next
RichTextBox1.Text = String.Join(Environment.NewLine, words.ToArray)
End Sub
For Each Word As String In thetext.Split(" ")
For Each key As String In keywords
If Word.StartsWith(key) Then
newTextLines.Add(Word)
Continue For
End If
Next
Next
or using LINQ:
Dim q = From word In thetext.Split(" ")
Where keywords.Any(Function(s) word.StartsWith(s))
Select word
RichTextBox1.Text = String.Join(Environment.NewLine, q.ToArray())
If don't know the keywords in advance but know in which context they occur, you can find them with a Regex expression. Two very handy Regex expressions allow you to find occurences succeeding or preceeding another:
(?<=prefix)find finds a pattern that follows another.
find(?=suffix) finds a pattern that comes before another.
If your number keyword (774) always preceeds " SIZE" you can find it like this: \w+(?=\sSIZE).
If the other keywords are always between "EX " and " DETAILS" you can find them like this: (?<=EX\s)(\w+\s)+(?=DETAILS).
You can put the whole thing together like this: \w+(?=\sSIZE)|(?<=EX\s)(\w+\s)+(?=DETAILS).
The disadvantage is that the keywords between "EX " and "DETAILS" will be returned as one match. But you can split the matches afterwards as in:
Const input As String = "2 3 3 4 4 A A B B SHEET 1 OF 1 774 SIZE SCALE 24.000-47.999 12.000-23.999 CON BAG WIRE 90in. EX Bos00232940 Bos00320491 Das1234 Das3216 DETAILS 1 2 RAGE"
Dim matches = Regex.Matches(input, "\w+(?=\sSIZE)|(?<=EX\s)(\w+\s)+(?=DETAILS)")
For Each m As Match In matches
Dim words = m.Value.Split(" "c)
For Each word As String In words
If word.Length > 0 Then ' Suppress the last empty word.
Console.WriteLine(word)
End If
Next
Next
Output:
774
Bos00232940
Bos00320491
Das1234
Das3216
How to do it with regular expression...
Dim re As New Regex("[\t ](?<w>((774)|(Bos)|(Das))[a-z0-9]*)[\t ]", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
Private Sub test()
Dim Lines() As String = {"2 3 3 4 4 A A B B SHEET 1 OF 1 774 SIZE SCALE 24.000-47.999 12.000-23.999 CON BAG WIRE 90in. EX Bos00232940 Bos00320491 Das1234 Das3216 DETAILS 1 2 RAGE"}
Dim words As New List(Of String)
For Each s As String In Lines
Dim mc As MatchCollection = re.Matches(s)
For Each m As Match In mc
words.Add(m.Groups("w").Value)
Next
Next
End Sub
Regex break down...
[\t ] Single tab or space (there is an alternative for whitespace too)
(?<w> Start of capture group called "w" This the the text returned later in the "m.Groups"
((774)|(Bos)|(Das)) one of the 3 blobs of text
[a-z0-9]* any a-z or 0-9 character, * = any number of them
) End of Capture group "w" from above.