I have documents that have AutoTextList fields. Unlike most fields, Fields(i).Code does not show the entire code. The Display Text / Literal Text does not show up when you display the field code nor does it report out in VBA.
I am trying to pull the components of this field and place into string variables.
The syntax of the field, when written, is:
{ AUTOTEXTLIST "Literal text" \s ["Style name"] \t ["Tip text"] }
I wrote the following macro to get a look at what can be found and how.
Sub LookAtAutoTextListField()
Dim i As Long
With ActiveDocument
For i = .Fields.Count To 1 Step -1
If .Fields(i).Type = wdFieldAutoTextList Then
Debug.Print "Display Text: " & .Fields(i).Result
Debug.Print "Code: " & .Fields(i).Code
End If
Next i
End With
End Sub
Here are four examples of the results:
1
Display Text: What I want
Code: AUTOTEXTLIST \s Normal \t ""How much""
2
Display Text: What I want
Code: AUTOTEXTLIST \s "Normal" \t ""How much""
3
Display Text: What I want
Code: AUTOTEXTLIST \s "Body Text" \t "Right-click to choose how much"
4
Display Text: What I want
Code: AUTOTEXTLIST \s "Body Text" \t ""How much""
I can easily put the Display text in a string.
The pop-up tip text can have slashes or not. When inserted using the insert field, it will have backslashes front and back. See all but example 3 above.
The style name may or may not have quotation marks around it. It must have them if the style name contains a space, but otherwise they are not required but can be used. See examples 1 and 2 above.
I would like to get the text between \s and \t stripping out quotation marks and the text following \t stripping out quotation marks and the backslashes.
I can find the location of the \s in the code using the Instr function and the left and right position of the \t in the code using Instr and InstrRev functions. I can get the length of what is reported for the code using the Len function.
I can use that information, together with the Left and Right functions to get the text between \s and \t (i.e. the Style) but need to strip out any Quotation marks which may or may not be present. I don't know how to do that.
I can do the same thing with the tip text, but don't know how to strip out any quotation marks and backslashes.
You could use code along the following lines (not well tested, e.g. I haven't checked what happns with an option value that starts with a " but has no terminating " - probably terminated by the end-of-field marker) as long as you know you are dealing with a "typical" field code, e.g. the sort that Word itself might create, where there is white space between the various elements of the field, the white space is all composed of regular spaces, and multi-word strings are enclosed by straight double quotation marks (chr(34)).
FWIW here I don't see quite what you describe when entering this field type from the field dialog box. I never see \t ""How much"". If I enter the tip text without quotation marks in the dialog box, I see \t "How much" and the quotation marks are not displayed in the tip. If I enter the tip text with quotation marks in the dialog box, I see \t "\"How much\"" and the quotation marks are displayed in the tip.
Sub testgetfieldparts()
' pass an autotextlistfield object
Call getAutotextlistFieldParts2(ActiveDocument.Fields(1))
End Sub
Sub getAutotextlistFieldParts(f As Word.Field)
Const FieldCodeName As String = "AUTOTEXTLIST"
Dim i As Long
Dim s As String
Dim StyleName As String
Dim TipText As String
If f.Type = WdFieldType.wdFieldAutoTextList Then
s = f.Code
i = InStr(1, UCase(s), FieldCodeName)
s = Trim(Mid(s, i + Len(FieldCodeName)))
i = InStr(1, LCase(s), "\s")
Debug.Print "Style Name: ";
If i = 0 Then
Debug.Print "No \s option specified"
Else
StyleName = OptionValue(s, i + 2)
If StyleName = "" Then
Debug.Print "\s option specified but no name specified"
Else
Debug.Print StyleName
End If
End If
i = InStr(1, LCase(s), "\t")
Debug.Print "Tip Text: ";
If i = 0 Then
Debug.Print "No \t option specified"
Else
TipText = OptionValue(s, i + 2)
If TipText = "" Then
Debug.Print "\t option specified but no text specified"
Else
Debug.Print TipText
End If
End If
Else
Debug.Print "Not an " & FieldCodeName & " field."
End If
End Sub
Function OptionValue(s As String, iStart As Long) As String
Dim c As String
Dim i As Long
Dim escape As Boolean
OptionValue = ""
escape = False
s = Trim(Mid(s, iStart))
c = Left(s, 1)
Select Case c
Case """"
For i = 2 To Len(s)
c = Mid(s, i, 1)
If escape Then
OptionValue = OptionValue & c
escape = False
Else
If c = """" Then
Exit For
Else
If c = "\" Then
escape = True
Else
OptionValue = OptionValue & c
End If
End If
End If
Next
Case "\" ' for now, assume this is the start of another option
'
Case Else
OptionValue = OptionValue & c
For i = 2 To Len(s)
c = Mid(s, i, 1)
If c = "\" Or c = " " Or c = """" Then
Exit For
Else
OptionValue = OptionValue & c
End If
Next
End Select
End Function
If you had to deal with what is actually allowed in a Word field code rather than what you will typically find, things get considerably more complicated, for at least the following reasons in Word's "field code language":
Word generally recognises 6 different Unicode characters as double quotation marks for enclosing strings, not just ". It doesn't recognise any single quotation marks for that purpose. You can use any of the 6 to start a string and any of the 6 to end one - they don't have to match in any way.
Word recognises at least 11 Unicode characters as "white space". The VBA Trim, LTrim and RTrim functions don't remove most of them.
Inside quoted strings, the backslash character \ generally acts as an escape character, so you can insert a \" in the middle of a string to get a " character. But outside quoted strings, backslash will generally be seen as the start of a new option and will act as a string terminator for any unquoted string.
You can put all sorts of non-text items in a field, e.g. inline images, content controls etc. It may not make sense in any given field to do that, but in a complete field parsing solution you might have to deal with such things. It isn't uncommon to use nested fields (e.g. you could specify the Style Name and Tip Text that way. In that case, the field result is generally as a "spaceless string" so even if the result contains spaces you do not have to put quotation marks around it. So you cannot treat the field result in the same way as you would treat its plain text result. There is more...
in some case you don't actually need any white space in the field. e.g. I think {AUTOTEXTLIST\sMyStyle\tImportantTip} would work. So a parser shouldn't rely on the presence of white space to separate tokens in the field.
Word doesn't always (ever?) prevent you from having multiple instances of the same option. In some cases that's deliberate (e.g. it's how you can include multiple books in a CITATION field.). But say you had two \t options in your AUTOTEXTLIST. In that case Word uses the first one unless no tip text is given, i.e. \t tip1 \t tip2 should display tip1 but \t \t tip2 will display tip2. AFAICS \s Style1 \s Style2 uses Style1 but I couldn't work out what \s \s Style2 was doing.
ANd there are doubtless exceptions to all that lot too. I have some code that deals with some of those issues but it isn't complete or well-tested.
Related
I'm trying to make a simple text converter program for my first Visual Basic program. I've already written this in Python but I'm not sure how to do it in Visual Basic.
I need the program to run through the characters of a string and once it encounters a ( to then remove the bracket and ignore the rest of the text until it encounters a ).
For Example,
"This is a (not so good) sentence",
becomes
"This is a Sentence".
Previously I did this with a for loop what looked at a character in the string, then checked if it was open. If it wasn't it would append the character to an output string to the next character or if it was it would then trigger a Boolean to true what would stop the character being appended. It would then continue to stop the future characters from being appended until it found a close bracket. At that point, it would then make the Boolean false, stop the closed bracket from being appended and move back to appending characters, unless it was another bracket.
Sorry if this description is a bit rough as I'm not the best at describing things and I'm very new to visual basic. Thanks for any help given
You can achieve this by several different methods. Here is one method using Instr. Instr returns the character position (index) of a given string in another string. You can use this to determine the bounds of where to include/exclude the string chunk.
You didn't specify if there could be multiple sections encapsulated in () so I assumed there wouldn't be. However, this is a relatively easy tweak by adding either a Do...Loop or a While... loop in the Function.
Hope it helps:
Option Explicit
Public Function removeBrackets(Source As String, Optional RemoveDoubleSpaces As Boolean = False)
Dim FirstBracket As Long
Dim SecondBracket As Long
FirstBracket = InStr(1, Source, "(")
SecondBracket = InStr(1, Source, ")")
If FirstBracket >= SecondBracket Or FirstBracket = 0 Or SecondBracket = 0 Then Exit Function
removeBrackets = Left$(Source, FirstBracket - 1) & Right$(Source, Len(Source) - SecondBracket)
If RemoveDoubleSpaces Then removeBrackets = Replace$(removeBrackets, " ", " ")
End Function
'Run this
Sub Test()
Debug.Print "The value returned is: " & removeBrackets("This is a (not so good) sentence") ' Example given
Debug.Print "The value returned is: " & removeBrackets("This is a (not so good) sentence", True) ' Example given, slight revision. Remove double spaces
Debug.Print "The value returned is: " & removeBrackets("This is a (not so good sentence") ' missing ending bracket
Debug.Print "The value returned is: " & removeBrackets("This is a not so good) sentence") ' missing starting bracket
Debug.Print "The value returned is: " & removeBrackets("This is a not so good sentence") ' No brackets
End Sub
I created a macro for removing all whitespace in a string, specifically an email address. However it only removes about 95% of the whitespace, and leaves a few.
My code:
Sub NoSpaces()
Dim w As Range
For Each w In Selection.Cells
w = Replace(w, " ", "")
Next
End Sub
Things I have tried to solve the issue include:
~ Confirmed the spaces are indeed spaces with the Code function, it is character 32 (space)
~ Used a substitute macro in conjuction with the replace macro
~ Have additional macro utilizing Trim function to remove leading and trailing whitespace
~ Made a separate macro to test for non-breaking spaces (character 160)
~ Used the Find and Replace feature to search and replace spaces with nothing. Confirmed working.
I only have one cell selected when I run the macro. It selects and goes through all the cells because of the Selection.Cells part of the code.
A few examples:
1 STAR MOVING # ATT.NET
322 TRUCKING#GMAIL.COM
ALEZZZZ#AOL. COM.
These just contain regular whitespace, but are skipped over.
Just use a regular expression:
'Add a reference to Microsoft VBScript Regular Expressions 5.5
Public Function RemoveWhiteSpace(target As String) As String
With New RegExp
.Pattern = "\s"
.MultiLine = True
.Global = True
RemoveWhiteSpace = .Replace(target, vbNullString)
End With
End Function
Call it like this:
Sub NoSpaces()
Dim w As Range
For Each w In Selection.Cells
w.Value = RemoveWhiteSpace(w.Value)
Next
End Sub
Try this:
Sub NoSpaces()
Selection.Replace " ", ""
End Sub
Use "Substitute"
Example...
=SUBSTITUTE(C1:C18," ","")
Because you assume that Selection.Cells includes all cells on the sheet.
Cells.Replace " ", ""
And to add to the excellent advice from all the great contributors, try the
TRIM or LTRIM, or RTRIM and you can read more about these functions here:
https://msdn.microsoft.com/en-us/library/office/gg278916.aspx
Now this does not remove embedded spaces (spaces in between the letters) but it will remove any leading and trailing spaces.
Hope this helps.
Space Problem with Excel
ok, the only way i see this two types of space is by converting their Ascii code value of which I do it here
now to explain this function i made, it will just filter the string character by character checking if its equal to the two types of space i mentioned. if not it will concatenate that character into the string which will be the final value after the loop. hope this helps. Thanks.
Function spaceremove(strs) As String
Dim str As String
Dim nstr As String
Dim sstr As String
Dim x As Integer
str = strs
For x = 1 To VBA.Len(str)
sstr = Left(Mid(str, x), 1)
If sstr = " " Or sstr = " " Then
Else
nstr = nstr & "" & sstr
End If
Next x
spaceremove = nstr
End Function
I copied a HTML table with data and pasted in excel but the cells were filled with unwanted space and all methods posted here didn't work so I debugged and I discovered that it wasn't actually space chars (ASCII 32) it was Non-breaking space) (ASCII 160) or HTML
So to make it work with that Non-breaking space char I did this:
Sub NoSpaces()
Dim w As Range
For Each w In Selection.Cells
w.Value = Replace(w.Value, " ", vbNullString)
w.Value = Replace(w.Value, Chr(160), vbNullString)
Next
End Sub
I wrote a custom function that parses an HL7 interface message. These are messages sent between healthcare information systems, but basically it's just a long text string, delimited with various characters to indicate different fields, that I paste into a cell in Excel. The function I created searches and counts to find the fields specified in the arguments.
DISCLAIMER: I am new to VBA. I've been teaching myself via online research and trial-and-error over the past 3-4 weeks, so I'm no VBA expert. I'd prefer NOT to use arrays because when I tried that, the code got too complex for me to troubleshoot. So, I'm OK with the code being easy-to-follow, as opposed to being the fastest/most-efficient.
Anyhow, I've got it working pretty well to do what I want, but I'm stuck on adding in logic for an OPTIONAL argument.
So, this is how I WANT it to work:
Formula =KWHL7(A1, "MSH", 8)
NOTE only 3 arguments
Result I Want ADT^A08
Result I Get ADT
NOTE I know I told it to stop at the next instance of "HL7_SUBFIELD_DELIMITER" which is " ^ "
Formula =KWHL7(A1, "MSH", 8,1)
NOTE the optional 4th argument
Result I Want ADT
Formula =KWHL7(A1, "MSH", 8,2)
NOTE the optional 4th argument
Result I Want A08
The contents "value" of cell A1:
<11>MSH|^~\&|OPS|384|RISIC|384|20160923093012||ADT^A08|Q1230569238T1410271390|P|2.3|||*PM_ALLERGY*|||8859/1<13>
EVN||20160923<13>
PID|1||000000808^^^SCH MRN^MRN^SC||ZZTEST^LEANN||20160706|F|||459 CORPORATION ST.^^BEAVER^PA^15009^USA||(724)775-7418^PRN|||S||000000008082^^^SCH Account Number^FIN NBR|||||||0<13>
PV1|1|I|SCH Periop^^^^^^||||08888^Bullian^Leann~08888^Naylor^Daniel|||10|||||||08888^Nguyen-potter^Rose~00187^TEST^STCHRISRES^L^MD^^MD^^SCH Doc Number|1|1287593^^^TEMP FIN^VISITID||||||||||||||||||||384||A|||20160707131900<13>
PV2|||PA^<13>
OBX|1||Dosing Weight^WEIGHT||5|kg<13>
OBX|2||Height^HEIGHT||25|cm<13>
AL1|1|Drug|d00308^morphine^Multum Drug||66382015<13>
ZAL|||16655315|16655315||Active|66382015^Anaphylaxis^673967||||20160923093008|^Naylor^Daniel|0<13>
AL1|3|Drug|d00012^codeine^Multum Drug||103576018<13>
ZAL|||16655323|16655307||Active|103576018^Diarrhea^673967||||20160923093008|^Naylor^Daniel|0<13>
<28><13>
My VBA code (sorry for all the comments, I'm just learning!):
Public Function KWHL7(KW_Cell_With_HL7_Message As Variant, KW_HL7_Segment_Name As String, KW_HL7_Field_Number As Integer)
'KW_Cell_With_HL7_Message = KW_Cell_With_HL7_Message.Value
'KW_Cell_With_HL7_Message = ActiveCell.Value
'KW_HL7_Segment_Name = "PID"
'KW_HL7_Field_Number = 18
Const HL7_SEGMENT_DELIMITER = vbLf 'using "<13>" did not work due to carriage return
Const HL7_FIELD_DELIMITER = "|" ' Pipe means next field
Const HL7_SUBFIELD_DELIMITER = "^"
'Various carriage returns and line breaks: vbLf, vbCr, vbCrLf, vbNewLine, Chr(10), Chr(13)
KWSegmentStringToSearchFor = HL7_SEGMENT_DELIMITER & KW_HL7_Segment_Name 'Using the segment delimiter ("<13>" or "vbLf" / carriage return) before segment name implies that the segment / line STARTS with this text
KWSegmentCharacterPosition = InStr(1, KW_Cell_With_HL7_Message, KWSegmentStringToSearchFor)
'** FOR TESTING ** MsgBox ("Segment Character Position: " & KWSegmentCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWSegmentCharacterPosition, 5))
'Now we have the character position of the start of the proper SEGMENT / line
'Now we have to find the Proper Field in that segment
'So we'll use this position + the length of the end of the Segment Delimiter as the start
'***WARNING***: Still must add logic to make sure we stop if we encounter another Segment Delimiter
KWFieldCharacterPosition = KWSegmentCharacterPosition + Len(HL7_SEGMENT_DELIMITER) 'instead of starting at character 0, start at the beginning of the segment found previously
' ** FOR TESTING ** MsgBox ("Length of Segment Delimiter = " & Len(HL7_SEGMENT_DELIMITER))
' ** FOR TESTING ** MsgBox ("Field Character Position: " & KWFieldCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWFieldCharacterPosition, 5))
For J = 1 To KW_HL7_Field_Number
KWFieldCharacterPosition = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_FIELD_DELIMITER)
If KWFieldCharacterPosition = 0 Then Exit For
Next
' ** FOR TESTING ** MsgBox ("Field Character Position: " & KWFieldCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWFieldCharacterPosition, 5))
'Determine the number of characters to return after the start position
'Want to pull text UNTIL the next Segment Delimiter or Field Delimiter or Subfield Delimiter
'Find the position of the next Segment Delimiter or Field Delimiter or Subfield Delimiter
'Since the InStr function does not accept multiple substrings to search for, and does not allow OR statements inside...
Next_HL7_Segment_Delimiter = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_SEGMENT_DELIMITER)
Next_HL7_Field_Delimiter = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_FIELD_DELIMITER)
Next_HL7_Subfield_Delimiter = InStr(KWFieldCharacterPosition + 1, KW_Cell_With_HL7_Message, HL7_SUBFIELD_DELIMITER)
'Added logic to handle issue where the next delimiter was not found, making result 0, making it the lowest value in the next lines of code
If Next_HL7_Segment_Delimiter = 0 Then Next_HL7_Segment_Delimiter = 99999
If Next_HL7_Field_Delimiter = 0 Then Next_HL7_Field_Delimiter = 99999
If Next_HL7_Subfield_Delimiter = 0 Then Next_HL7_Subfield_Delimiter = 99999
'Set the Last Character Position to whichever Next Delimiter is the lowest / minimum number - Segment or Field or Subfield
KWLastCharacterPosition = WorksheetFunction.Min(Next_HL7_Segment_Delimiter, Next_HL7_Field_Delimiter, Next_HL7_Subfield_Delimiter)
' ** FOR TESTING ** MsgBox ("Last Character Position: " & KWLastCharacterPosition & ", 5 Characters starting there = " & Mid(KW_Cell_With_HL7_Message, KWLastCharacterPosition, 5))
'Determine the number of characters to return in the MID function by subtracting the first character position from the last character position
KWNumberOfCharactersToReturn = KWLastCharacterPosition - KWFieldCharacterPosition - 1
' ** FOR TESTING ** MsgBox ("Number of characters to return: " & KWNumberOfCharactersToReturn)
KWResult = Mid(KW_Cell_With_HL7_Message, KWFieldCharacterPosition + 1, KWNumberOfCharactersToReturn)
'MsgBox ("Result: Segment " & KW_HL7_Segment_Name & ":" & KW_HL7_Field_Number & " is " & KWResult)
KWHL7 = KWResult
End Function
The problem I had with using the split function was that it put everything into arrays. And since I needed to search FIRST for the KWSegmentStringToSearchFor (i.e. "MSH" or "PV1"), before couting the pipe (|) characters, I would need the array to have separate nested arrays and it got way too confusing for me.
So I abandoned the split function, and my initial plans to use arrays, and just wrote everything to find things sequentially. So it searches for the KWSegmentStringToSearchFor (i.e. "MSH" or "PV1") with InStr() and then counts the pipe (|) characters from there to determine which number field to return.
Since the strings are of variable length, but delimited with special characters, next I have to determine how many characters to return with the MID function. So I search for the next delimiter FROM THERE / using the field I found as the starting point and call that the end of my field.
The issue:
The logic considers ANY of the 3 possible delimiters the end of the field.
If I take that out, the code wouldn't know where the end of the string is.
Even if I add some sort of IF statement that IF the optional 4th argument exists (which I'm not sure how to do yet), THEN ignore the ^ as a delimiter... that would always return the full field (ADT^A08). It wouldn't return just the sub-field / component I want.
Thanks!
A simple answer, would be to split on the LineFeed then it may need tweaking would be, split(range("a1").value,"|")(intFieldNumber)
i.e.
split("11>MSH|^~\&|OPS|384|RISIC|384|20160923093012||ADT^A08|Q1230569238T1410271390","|")(8)
gives the result ADT^A08
please try to specifically answer my question and not offer alternative approaches as I have a very specific problem that needs this ad-hoc solution. Thank you very much.
Automatically my code opens Word through VB.NET, opens the document, finds the table, goes to a cell, moves that cells.range.text into a String variable and in a For loop compares character at position p to a String.
I have tried Strings:
"^p", "^013", "U+00B6"
My code:
Dim nextString As String
'For each cell, extract the cell's text.
For p = 17 To word_Rng.Cells.Count
nextString = word_Rng.Cells(p).Range.Text
'For each text, search for structure.
For q = 0 To nextString.Length - 1
If (nextString.Substring(q, 1) = "U+00B6") Then
Exit For
End If
Next
Next
Is the structural data lost when assigning the cells text to a String variable. I have searched for formatting marks like this in VBA successfully in the past.
Assuming that your string contains the character, you can use ChrW to create the appropriate character from the hex value, and check for that:
If nextString.Substring(q, 1) = ChrW(&h00B6) Then
Exit For
End If
UPDATE
Here's a complete example:
Dim nextString = "This is a test " & ChrW(&H00B6) & " for that char"
Console.WriteLine(nextString)
For q = 0 To nextString.Length - 1
If nextString(q) = ChrW(&H00B6) Then
Console.WriteLine("Found it: {0}", q)
End If
Next
This outputs:
This is a test ¶ for that char
Found it: 15
I am writing a program in Visual Basic 2010 that lists how many times a word of each length occurs in a user-inputted string. Although most of the program is working, I have one problem:
When looping through all of the characters in the string, the program checks whether there is a next character (such that the program does not attempt to loop through characters that do not exist). For example, I use the condition:
If letter = Microsoft.VisualBasic.Right(input, 1) Then
Where letter is the character, input is the string, and Microsoft.VisualBasic.Right(input, 1) extracts the rightmost character from the string. Thus, if letter is the rightmost character, the program will cease to loop through the string.
This is where the problems comes in. Let us say the string is This sentence has five words. The rightmost character is an s, but an s is also the fourth and sixth character. That means that the first and second s will break the loop just as the others will.
My questions is whether there is a way to ensure that only the last s, or whatever character is the last one in the string can break the loop.
There are a few methods you can use for this, one as Neolisk shows; here are a couple of others:
Dim breakChar As Char = "s"
Dim str As String = "This sentence has five words"
str = str.Replace(".", " ")
str = str.Replace(",", " ")
str = str.Replace(vbTab, " ")
' other chars to replace
Dim words() As String = str.ToLower.Split(New Char() {" "}, StringSplitOptions.RemoveEmptyEntries)
For Each word In words
If word.StartsWith(breakChar) Then Exit For
Console.WriteLine("M1 Word: ""{0}"" Length: {1:N0}", word, word.Length)
Next
If you need to loop though chars for whatever reason, you can use something like this:
Dim breakChar As Char = "s"
Dim str As String = "This sentence has five words"
str = str.Replace(".", " ")
str = str.Replace(",", " ")
str = str.Replace(vbTab, " ")
' other chars to replace
'method 2
Dim word As New StringBuilder
Dim words As New List(Of String)
For Each c As Char In str.ToLower.Trim
If c = " "c Then
If word.Length > 0 'support multiple white-spaces (double-space etc.)
Console.WriteLine("M2 Word: ""{0}"" Length: {1:N0}", word.ToString, word.ToString.Length)
words.Add(word.ToString)
word.Clear()
End If
Else
If word.Length = 0 And c = breakChar Then Exit For
word.Append(c)
End If
Next
If word.Length > 0 Then
words.Add(word.ToString)
Console.WriteLine("M2 Word: ""{0}"" Length: {1:N0}", word.ToString, word.ToString.Length)
End If
I wrote these specifically to break on the first letter in a word as you ask, adjust as needed.
VB.NET code to calculate how many times a word of each length occurs in a user-inputted string:
Dim sentence As String = "This sentence has five words"
Dim words() As String = sentence.Split(" ")
Dim v = From word As String In words Group By L = word.Length Into Group Order By L
Line 2 may need to be adjusted to remove punctuation characters, trim extra spaces etc.
In the above example, v(i) contains word length, and v(i).Group.Count contains how many words of this length were encountered. For debugging purposes, you also have v(i).Group, which is an array of String, containing all words belonging to this group.