vb.net Word Table Formatting - vb.net

I have been trying to figure out how to force word tables to under line until the end of the cell. I appear to be having issues if lines are to long and/or to short. I am not a word expert, however I am assuming that all characters are not the same size...
This is what the code produces
Below is the code I used to create the above. I would think that I should be able to check the cell length? Any help would be appreciated.
Public Shared Sub CreateWordDocument()
Try
Dim oWord As Word.Application
Dim oDoc As Word.Document
'Start Word and open the document template.
oWord = CreateObject("Word.Application")
oWord.Visible = True
oDoc = oWord.Documents.Add
Dim Row As Integer, Column As Integer
Dim myTable As Word.Table = oDoc.Tables.Add(oDoc.Bookmarks.Item("\endofdoc").Range, 10, 2)
myTable.Range.ParagraphFormat.SpaceAfter = 1
Dim mystring As String = "This is my Test name That Runs over to the next line"
Dim address1 As String = "123 1st fake street"
Dim address2 As String = "Fake town place"
Dim mystring2 As String = "This is good line"
Dim address3 As String = "321 3rd fake street"
Dim address4 As String = "Fake town place"
Dim line As String = "_"
For Row = 1 To 10
If Row <> 5 Then
myTable.Rows.Item(Row).Range.Font.Underline = Word.WdUnderline.wdUnderlineSingle
myTable.Rows.Item(Row).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft
myTable.Rows.Item(Row).Range.Font.Bold = False
myTable.Rows.Item(Row).Range.Font.Size = 11
myTable.Rows.Item(Row).Range.Font.Underline = Word.WdUnderline.wdUnderlineSingle
End If
For Column = 1 To 2
If Column = 1 And Row = 1 Then
myTable.Cell(Row, Column).Range.Text = GetString(mystring)
ElseIf Column = 1 And Row = 2 Then
myTable.Cell(Row, Column).Range.Text = GetString(address1)
ElseIf Column = 1 And Row = 3 Then
myTable.Cell(Row, Column).Range.Text = GetString(address2)
ElseIf Column = 2 And Row = 1 Then
myTable.Cell(Row, Column).Range.Text = GetString(mystring2)
ElseIf Column = 2 And Row = 2 Then
myTable.Cell(Row, Column).Range.Text = GetString(address3)
ElseIf Column = 2 And Row = 3 Then
myTable.Cell(Row, Column).Range.Text = GetString(address4)
Else
myTable.Cell(Row, Column).Range.Text = GetString(line)
End If
Next
Next
Dim strCellText As String
Dim uResp As String
Dim itable As Table
For Each itable In oDoc.Tables
uResp = ""
For Row = 1 To itable.Rows.Count
For Col = 1 To itable.Columns.Count
strCellText = itable.Cell(Row, Col).Range.Text
If strCellText.Length >= 33 Then
Console.Write("this will be on a different line")
ElseIf strCellText.Length <= 31 Then
Console.Write("this will be on a different line")
End If
Next
Next
Next
Catch ex As Exception
End Try
End Sub
Public Shared Function GetString(ByVal strGetLine As String) As String
If strGetLine.Length <> 30 Then
Do Until strGetLine.Length >= 30
strGetLine += "_"
Dim count As String = strGetLine.Length
Loop
End If
Return strGetLine
End Function

There are two parts to your problem. One is the font. Because you are padding each line with "_" to a predetermined width, you must use a monospaced font or the lines will end unevenly. With a monospaced font, each character will take up the same width which will give you your uniform lines. Second, the GetString function takes any line less than 30 characters and pads it, but it does not handle any lines that are over 30 characters which is why the line wraps by itself. To solve these two problems, I set the font to a monospaced font (Courier New in this case) and modified the GetString function's logic. Now, if the line is more than 30 characters, the function will find a space where it can split the string as close as possible to the 30-char limit and add a break there, before padding both lines with underscores. Here is your code with the changes included:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Added these two Dim's so I could run your example
Dim oWord As Object
Dim oDoc As Document
oWord = CreateObject("Word.Application")
oWord.Visible = True
oDoc = oWord.Documents.Add
Dim Row As Integer, Column As Integer
Dim myTable As Word.Table = oDoc.Tables.Add(oDoc.Bookmarks.Item("\endofdoc").Range, 10, 2)
myTable.Range.ParagraphFormat.SpaceAfter = 1
Dim mystring As String = "This is my Test name That Runs over to the next line"
Dim address1 As String = "123 1st fake street"
Dim address2 As String = "Fake town place"
Dim mystring2 As String = "This is good line"
Dim address3 As String = "321 3rd fake street"
Dim address4 As String = "Fake town place"
Dim line As String = "_"
For Row = 1 To 10
'Removed this If, because all lines need font set to ensure same width, even if line has no text
'If Row <> 5 Then
myTable.Rows.Item(Row).Range.Font.Underline = Word.WdUnderline.wdUnderlineSingle
myTable.Rows.Item(Row).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft
myTable.Rows.Item(Row).Range.Font.Bold = False
myTable.Rows.Item(Row).Range.Font.Size = 11
myTable.Rows.Item(Row).Range.Font.Underline = Word.WdUnderline.wdUnderlineSingle
myTable.Rows.Item(Row).Range.Font.Name = "Courier New" 'Set font to a monospaced font
'End If
For Column = 1 To 2
If Column = 1 And Row = 1 Then
myTable.Cell(Row, Column).Range.Text = GetString(mystring)
ElseIf Column = 1 And Row = 2 Then
myTable.Cell(Row, Column).Range.Text = GetString(address1)
ElseIf Column = 1 And Row = 3 Then
myTable.Cell(Row, Column).Range.Text = GetString(address2)
ElseIf Column = 2 And Row = 1 Then
myTable.Cell(Row, Column).Range.Text = GetString(mystring2)
ElseIf Column = 2 And Row = 2 Then
myTable.Cell(Row, Column).Range.Text = GetString(address3)
ElseIf Column = 2 And Row = 3 Then
myTable.Cell(Row, Column).Range.Text = GetString(address4)
Else
myTable.Cell(Row, Column).Range.Text = GetString(line)
End If
Next
Next
Dim strCellText As String
Dim uResp As String
Dim itable As Table
For Each itable In oDoc.Tables
uResp = ""
For Row = 1 To itable.Rows.Count
For Col = 1 To itable.Columns.Count
strCellText = itable.Cell(Row, Col).Range.Text
If strCellText.Length >= 33 Then
Console.Write("this will be on a different line")
ElseIf strCellText.Length <= 31 Then
Console.Write("this will be on a different line")
End If
Next
Next
Next
End Sub
Public Shared Function GetString(ByVal strGetLine As String) As String
'If strGetLine.Length <> 30 Then
' Do Until strGetLine.Length >= 30
' strGetLine += "_"
' Dim count As String = strGetLine.Length
' Loop
'End If
'New Function Logic:
'If the line is just a blank line, then just send back 30 underscores
If strGetLine.Trim.Equals("_") Then Return strGetLine.PadRight(30, "_")
Dim ret As String = Nothing
If strGetLine.Length > 30 Then
Dim lineBreak As Integer = 0
If strGetLine.Length >= 30 Then
Dim i As Integer = 0
Do While i <= 30
i = strGetLine.IndexOf(" ", i + 1)
If i <= 30 Then lineBreak = i
Loop
End If
ret = strGetLine.Substring(0, lineBreak).Trim.PadRight(30, "_") & vbCrLf
ret &= strGetLine.Substring(lineBreak, strGetLine.Length - lineBreak).Trim.PadRight(30, "_")
Else
ret = strGetLine.PadRight(30, "_")
End If
Return ret
End Function
Which outputs:
Now I'm sure you'll notice, there appears to be a blank line in the right column (the rest of the blank lines are from the 10 row loop). This is simply because the other column of the same row has two lines. I don't know if that's what you would want or not, but if you want both columns to have the appearance of the same number of lines, you will have to keep track of if you split a line in column 1, and add an extra blank line to column two...but this should get you going in the right direction

Related

Inserting Line Break to the nearest space after a set of character length is set

I have come across this code(not mine), what it actually does is insert a Line break after a character length has been determined.
Public Function LFNearSpace(InputStr As String, CharCnt As Long)
Dim SplitStrArr() As Variant
Dim SplitCnt As Long
Dim c As Long
Dim i As Long
Dim Lcnt As Long
Dim Rcnt As Long
Dim OutputStr As String
'Split string into Array
ReDim SplitStrArr(Len(InputStr) - 1)
For i = 1 To Len(InputStr)
SplitStrArr(i - 1) = Mid$(InputStr, i, 1)
Next
SplitCnt = 0
For c = LBound(SplitStrArr) To UBound(SplitStrArr)
SplitCnt = SplitCnt + 1
If SplitCnt = CharCnt Then
'get count to space nearest to the left and right of word
For i = c To LBound(SplitStrArr) Step -1
If SplitStrArr(i) = " " Then
Lcnt = i
Exit For
End If
Next i
For i = c To UBound(SplitStrArr)
If SplitStrArr(i) = " " Then
Rcnt = i
Exit For
End If
Next i
'add line feed to nearest space
If (Rcnt - c) < (c - Lcnt) Then
SplitStrArr(Lcnt) = Chr(10)
SplitCnt = c - Lcnt
ElseIf (Rcnt - c) = (c - Lcnt) Then
SplitStrArr(Rcnt) = Chr(10)
SplitCnt = c - Rcnt
End If
End If
Next c
'Finalize the output into a single string
LFNearSpace = Join(SplitStrArr, "")
End Function
So here's my condition:
Column Width: 75
Font Name: Arial
Font Size: 9
I am customizing it for a while to fit my conditions,as far as I can think of
Unfortunately, the function cuts(inserts line break) the word not in natural way for example:
I call it like this, well if I change the 105 value the output changes but I wanted to create a solution why the output is similar to the image below.
SomeStr = LFNearSpace(SomeStr, 105)
Worksheets("Sheet1").Range("A1").Value = SomeStr
Any thoughts? Thanks
Try this
With Columns(1)
.ColumnWidth = 75
.Font.Name = "Arial"
.Font.Size = 9
.WrapText = True
End With
below code will break string to two line on occurrence of space after 20 character.
dim inputstr as string = "This is my test input string. I hope it helps!"
dim breakafter as integer= 20
dim line1 as string,line2 as string
dim found as integer=InStr(breakafter, inputstr, " ", vbTextCompare) ' KNOW WHERE IS 1st space after 20 char(s)
line1= Left(inputstr,found ) ' get 1st part of text
line2 = Replace(inputstr, " ", environment.newline() , found, 1, vbTextCompare) ' get remaining text
msgbox line1 + iif(isnothing(line2),"",line2)

Deleting duplicate text in a cell in excel

I was wondering how to remove duplicate names/text's in a cell. For example
Jean Donea Jean Doneasee
R.L. Foye R.L. Foyesee
J.E. Zimmer J.E. Zimmersee
R.P. Reed R.P. Reedsee D.E. Munson D.E. Munsonsee
While googling, I stumbled upon a macro/code, it's like:
Function RemoveDupes1(pWorkRng As Range) As String
'Updateby20140924
Dim xValue As String
Dim xChar As String
Dim xOutValue As String
Set xDic = CreateObject("Scripting.Dictionary")
xValue = pWorkRng.Value
For i = 1 To VBA.Len(xValue)
xChar = VBA.Mid(xValue, i, 1)
If xDic.exists(xChar) Then
Else
xDic(xChar) = ""
xOutValue = xOutValue & xChar
End If
Next
RemoveDupes1 = xOutValue
End Function
The macro is working, but it is comparing every letter, and if it finds any repeated letters, it's removing that.
When I use the code over those names, the result is somewhat like this:
Jean Dos
R.L Foyes
J.E Zimers
R.P edsDEMuno
By looking at the result I can make out it is not what I want, yet I got no clue how to correct the code.
The desired output should look like:
Jean Donea
R.L. Foye
J.E. Zimmer
R.P. Reed
Any suggestions?
Thanks in Advance.
Input
With the input on the image:
Result
The Debug.Print output
Regex
A regex can be used dynamically iterating on the cell, to work as a Find tool. So it will extract only the shortest match. \w*( OUTPUT_OF_EXTRACTELEMENT )\w*, e.g.: \w*(Jean)\w*
The Regex's reference must be enabled.
Code
Function EXTRACTELEMENT(Txt As String, n, Separator As String) As String
On Error GoTo ErrHandler:
EXTRACTELEMENT = Split(Application.Trim(Mid(Txt, 1)), Separator)(n - 1)
Exit Function
ErrHandler:
' error handling code
EXTRACTELEMENT = 0
On Error GoTo 0
End Function
Sub test()
Dim str As String
Dim objMatches As Object
Set objRegExp = CreateObject("VBScript.RegExp") 'New regexp
lastrow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row
For Row = 1 To lastrow
str = Range("A" & Row)
F_str = ""
N_Elements = UBound(Split(str, " "))
If N_Elements > 0 Then
For k = 1 To N_Elements + 1
strPattern = "\w*(" & EXTRACTELEMENT(CStr(str), k, " ") & ")\w*"
With objRegExp
.Pattern = strPattern
.Global = True
End With
If objRegExp.test(strPattern) Then
Set objMatches = objRegExp.Execute(str)
If objMatches.Count > 1 Then
If objRegExp.test(F_str) = False Then
F_str = F_str & " " & objMatches(0).Submatches(0)
End If
ElseIf k <= 2 And objMatches.Count = 1 Then
F_str = F_str & " " & objMatches(0).Submatches(0)
End If
End If
Next k
Else
F_str = str
End If
Debug.Print Trim(F_str)
Next Row
End Sub
Note that you can Replace the Debug.Print to write on the target
cell, if it is column B to Cells(Row,2)=Trim(F_str)
Explanation
Function
You can use this UDF, that uses the Split Function to obtain the element separated by spaces (" "). So it can get every element to compare on the cell.
Loops
It will loop from 1 to the number of elements k in each cell and from row 1 to lastrow.
Regex
The Regex is used to find the matches on the cell and Join a new string with the shortest element of each match.
This solution operates on the assumption that 'see' (or some other three-letter string) will always be on the end of the cell value. If that isn't the case then this won't work.
Function RemoveDupeInCell(dString As String) As String
Dim x As Long, ct As Long
Dim str As String
'define str as half the length of the cell, minus the right three characters
str = Trim(Left(dString, WorksheetFunction.RoundUp((Len(dString) - 3) / 2, 0)))
'loop through the entire cell and count the number of instances of str
For x = 1 To Len(dString)
If Mid(dString, x, Len(str)) = str Then ct = ct + 1
Next x
'if it's more than one, set to str, otherwise error
If ct > 1 Then
RemoveDupeInCell = str
Else
RemoveDupeInCell = "#N/A"
End If
End Function

VBA: Find red cells and copy header

Background: I have already used the 'conditional' formatting to highlight the 10 lowest values in each row in light red.
Now, I am trying to compose a code that searches each row for the red marked cells and copies their name from the header row to a new sheet.
What I am aiming for is the following: a code that searches each row for the cells in red and that copies the name (in header) to the same row in another sheet (=result sheet). This should result in a result sheet with 11 columns: first column being the dates and the following 10 columns in that row being the names of the lowest values for that date.
This is the code that I have so far but it does not work:
Sub CopyReds()
Dim i As Long, j As Long
Dim sPrice As Worksheet
Dim sResult As Worksheet
Set sPrice = Sheets("Prices")
Set sResult = Sheets("Result")
i = 2
For j = 2 To 217
Do Until i = 1086
If sPrice.Cells(j, i).Offset(j, 0).Interior.Color = 13551615 Then
sPrice.Cells(j, i).Copy Destination:=sResult.Cells(2, 2).Offset(j, 1)
End If
Loop
Next j
End Sub
Update: screenshot worksheet
Update 2: Screenshot result sample
I think your code should look something like this:
Option Explicit
Sub CopyReds()
Dim sPrice As Worksheet: Set sPrice = Sheets("Prices")
Dim sResult As Worksheet: Set sResult = Sheets("Result")
Const colPriceName As Long = 2 ' The column in which cells can be colored red and contains the names to copy
Const clrCopy As Long = 13551615 ' The color which indicates that the cell should be copied (red)
Const colResult As Long = 2 ' The column where the results should be copied
Const rowResultFirst As Long = 2 ' First row on sResult to use for output
Dim rowResult As Long: rowResult = rowResultFirst
Dim rowPrice As Long: For rowPrice = 2 To sPrice.UsedRange.Rows.Count - sPrice.UsedRange.Row + 1 ' Loop until last row
If DisplayedColor(sPrice.Cells(rowPrice, colPriceName)) = clrCopy Then
sResult.Cells(rowResult, colResult).Value = sPrice.Cells(rowPrice, colPriceName).Value
rowResult = rowResult + 1
End If
Next rowPrice
End Sub
Update: handling conditional formatting
If you use conditional formatting then VBA does not read the actual color displayed but the color which would be shown without Conditional Formatting. So you need a vehicle to determine the displayed color. I wrote this code based on this source but refactored it significantly, e.g. now it did not work in international environment and its readability was poor:
Function DisplayedColor(rngCell As Range, Optional bCellInterior As Boolean = True, Optional bReturnColorIndex As Long = False) As Long
Dim ewbTemp As Workbook: Set ewbTemp = Application.Workbooks.Add() ' Creates a new workbook, so that none of the cells of other workbooks is tampered with (not even temporarily) - this may be overkill, you may centralize this object or use existing cells
DisplayedColor = -1 ' Assume Failure and indicate Error
If 1 < rngCell.Count Then
Debug.Print "Error in DisplayedColor: rngCell contains more than 1 cell"
Exit Function
End If
Dim objTarget As Object: Set objTarget = rngCell
Dim i As Long: For i = 1 To rngCell.FormatConditions.Count
With rngCell.FormatConditions(i)
Dim bFormatConditionActive As Boolean: bFormatConditionActive = False
Dim varValue As Variant: varValue = rngCell.Value
Dim strFormula1 As String: strFormula1 = FormulaFromFormulaLocal(.Formula1, ewbTemp.Worksheets(1).Cells(1, 1))
Dim varEval1 As String: varEval1 = rngCell.Worksheet.Evaluate(strFormula1)
If .Type = xlCellValue Then
Select Case .Operator
Case xlEqual
bFormatConditionActive = varValue = varEval1
Case xlNotEqual
bFormatConditionActive = varValue <> varEval1
Case xlGreater
bFormatConditionActive = varValue > varEval1
Case xlGreaterEqual
bFormatConditionActive = varValue >= varEval1
Case xlLess
bFormatConditionActive = varValue < varEval1
Case xlLessEqual
bFormatConditionActive = varValue <= varEval1
Case xlBetween, xlNotBetween
Dim strFormula2 As String: strFormula2 = FormulaFromFormulaLocal(.Formula2, ewbTemp.Worksheets(1).Cells(1, 1))
Dim varEval2 As String: varEval2 = rngCell.Worksheet.Evaluate(strFormula2)
bFormatConditionActive = varEval1 <= varValue And varValue <= varEval2
If .Operator = xlNotBetween Then
bFormatConditionActive = Not bFormatConditionActive
End If
Case Else
Debug.Print "Error in DisplayedColor: unexpected Operator"
Exit Function
End Select
ElseIf .Type = xlExpression Then
bFormatConditionActive = varEval1
Else
Debug.Print "Error in DisplayedColor: unexpected Type"
Exit Function
End If
If bFormatConditionActive Then
Set objTarget = rngCell.FormatConditions(i)
Exit For
End If
End With
Next i
If bCellInterior Then
If bReturnColorIndex Then
DisplayedColor = objTarget.Interior.ColorIndex
Else
DisplayedColor = objTarget.Interior.Color
End If
Else
If bReturnColorIndex Then
DisplayedColor = objTarget.Font.ColorIndex
Else
DisplayedColor = objTarget.Font.Color
End If
End If
ewbTemp.Close False
End Function
Function FormulaFromFormulaLocal(strFormulaLocal As String, rngDummy As Range) As String
Dim strOldFormula As String: strOldFormula = rngDummy.Formula
rngDummy.FormulaLocal = strFormulaLocal
FormulaFromFormulaLocal = rngDummy.Formula
rngDummy.Formula = strOldFormula
End Function
Please also note the change in the If statement of CopyReds (now it calls the above function).
I think that your algorithm should be redesigned: instead of testing the cells displayed color, check if the value is below a limit. This limit can be calculated with WorksheetFunction.Small, which returns the n-th smallest element.
Sub CopyReds()
Dim sPrice As Worksheet: Set sPrice = Sheets("Prices")
Dim sResult As Worksheet: Set sResult = Sheets("Result")
Const colPriceName As Long = 2 ' The column in which cells can be colored red and contains the names to copy
Const clrCopy As Long = 13551615 ' The color which indicates that the cell should be copied (red)
Const colResult As Long = 2 ' The column where the results should be copied
Const rowResultFirst As Long = 2 ' First row on sResult to use for output
Const lngCount As Long = 10 ' Copy lngCount lowest elements (the actual number may be higher due to ties)
Const colSort As Long = 2 ' The column in which cells contain the values from which the lowest lngCount should be selected
Dim varLimit As Variant: varLimit = Application.WorksheetFunction.Small(sPrice.UsedRange.Cells(2, colSort).Resize(sPrice.UsedRange.Rows.Count - 1, 1), 10)
Dim rowResult As Long: rowResult = rowResultFirst
Dim rowPrice As Long: For rowPrice = 2 To sPrice.UsedRange.Rows.Count - sPrice.UsedRange.Row + 1 ' Loop until last row
If sPrice.Cells(rowPrice, colSort).Value <= varLimit Then
sResult.Cells(rowResult, colResult).Value = sPrice.Cells(rowPrice, colPriceName).Value
rowResult = rowResult + 1
End If
Next rowPrice
End Sub
Based on the screenshots, I revised the code:
Sub CopyReds()
Dim sPrice As Worksheet: Set sPrice = Sheets("Prices")
Dim sResult As Worksheet: Set sResult = Sheets("Result")
Const rowResultFirst As Long = 2 ' First row on sResult to use for output
Const rowPriceFirst As Long = 2 ' First row on sPrice to process
Const lngCount As Long = 10 ' Copy lngCount lowest elements (the actual number may be higher due to ties)
Const colDate As Long = 1 ' The column which contains the dates
Const colValueStart As Long = 2 ' The column where values start
Dim rowResult As Long: rowResult = rowResultFirst
Dim rowPrice As Long: For rowPrice = rowPriceFirst To sPrice.UsedRange.Rows.Count - sPrice.UsedRange.Row + 1 ' Loop until last row
Dim colResult As Long: colResult = 1
sResult.Cells(rowResult, colResult).Value = sPrice.Cells(rowPrice, colDate).Value
colResult = colResult + 1
Dim varLimit As Variant: varLimit = Application.WorksheetFunction.Small(sPrice.Cells(rowPrice, colValueStart).Resize(1, sPrice.UsedRange.Columns.Count - colValueStart + 1), lngCount)
Dim colPrice As Long: For colPrice = colValueStart To sPrice.UsedRange.Columns.Count - colValueStart + 1
If sPrice.Cells(rowPrice, colPrice).Value <= varLimit Then
sResult.Cells(rowResult, colResult).Value = sPrice.Cells(rowResultFirst - 1, colPrice).Value
colResult = colResult + 1
End If
Next colPrice
rowResult = rowResult + 1
Next rowPrice
End Sub
Just to clarify my comment, you need to "advance" either the Cells(j, i) or the Offset(j, 0).
If you decided to use For loops, try to stick with it for both cases:, see code below:
For j = 2 To 217
For i = 2 To 1086
Debug.Print sPrice.Cells(j, i).Interior.Color ' <-- for Debug only
If sPrice.Cells(j, i).Interior.Color = 13551615 Then
sPrice.Cells(j, i).Copy Destination:=sResult.Cells(2, 2).Offset(j, 1)
End If
Next i
Next j

How to separate/filter English text from Chinese in Excel

I am working on a project that includes multiples Excel files with cells containing English, Chinese, or both English and Chinese.
I need to keep the rows that are completely in Chinese and put them first. Then, I need lines with both Chinese characters and English. And only then those that are in English only.
I came across the following 3 functions that could help me mark the content accordingly, yet they do not seem to be working as expected, and I cannot figure out why.
Function ExtractChn(txt As String)
Dim i As Integer
Dim ChnTxt As String
For i = 1 To Len(txt)
If Asc(Mid(txt, i, 1)) < 0 Then
ChnTxt = ChnTxt & Mid(txt, i, 1)
End If
Next i
ExtractChn = ChnTxt
End Function
Function ExtractEng(txt As String)
Dim i As Integer
Dim EngTxt As String
For i = 1 To Len(txt)
If Asc(Mid(txt, i, 1)) >= 0 Then
EngTxt = EngTxt & Mid(txt, i, 1)
End If
Next i
ExtractEng = EngTxt
End Function
Function CheckTxt(txt)
Dim i As Integer
Dim Eng As Integer
Dim Chn As Integer
Chn = 0
Eng = 0
For i = 1 To Len(txt)
If Asc(Mid(txt, i, 1)) > 0 Then
Eng = 1
Else:
Chn = 1
End If
Next i
If Chn = 1 And Eng = 1 Then 'Contains Both Eng & Chn
CheckTxt = "BOTH"
Else:
If Chn = 1 And Eng = 0 Then 'Chn
CheckTxt = "CHN"
Else:
If Chn = 0 And Eng = 1 Then 'Eng
CheckTxt = "ENG"
End If
End If
End If
End Function
The person who created them even supplied a file demonstrating how the functions work. I am attaching the link to the file which has the arrangement as follows:
Text|English part of it|Chinese part of it|ExtractEng|ExtractChn|CheckTxt
According to the author's intentions, the CheckTxt result should display either CH, ENG, or BOTH. However, it is only displaying ENG at all times and I cannot figure why.
Any ideas how to make it work? Unless there is an easier way to 'advance-filter' the content in Excel? Any help will be much appreciated.
Test Excel file from the developer
This sounds like a job for Regular Expressions!!
Function getCharSet(Target As Range) As String
Const ChinesePattern = "[\u4E00-\u9FFF\u6300-\u77FF\u7800-\u8CFF\u8D00-\u9FFF]+"
Const EnglishPattern = "[A-Za-z]"
Dim results As String
Dim Data, v
Dim Regex1 As Object
Set Regex1 = CreateObject("VBScript.RegExp")
Regex1.Global = True
If Target.Count = 1 Then
Data = Array(Target.Value2)
Else
Data = Target.Value2
End If
For Each v In Data
If Not InStr(results, "CHN") Then
Regex1.Pattern = ChinesePattern
If Regex1.Test(v) Then
If Len(results) Then
getCharSet = "CHN" & " - " & results
Exit Function
Else
results = "CHN"
End If
End If
End If
If Not InStr(results, "ENG") Then
Regex1.Pattern = EnglishPattern
If Regex1.Test(v) Then
If Len(results) Then
getCharSet = results & " - ENG"
Exit Function
Else
results = "ENG"
End If
End If
End If
Next
getCharSet = results
End Function
A basic approach :
Sub Main()
Dim sh As Worksheet
Set sh = ActiveSheet
Dim rng As Range
Set rng = sh.Range("A6:D10")
Call Separate_English_Chinese(rng)
End Sub
Sub Separate_English_Chinese(rng)
Dim sh As Worksheet
Set sh = rng.Parent
Dim EnglishCharacters As String
Dim colEng As Long, colChn As Long, colContains As Long
Dim a As String, i As Long, k As Long
Dim colFullText As Long, txtEnglish As String, txtChinese As String
Dim Result As Long, Contains As String
Dim First As Long, Last As Long
First = rng.Row
Last = rng.Rows.Count + rng.Row - 1
EnglishCharacters = "qwertyuiopasdfghjklzxcvbnm"
EnglishCharacters = UCase(EnglishCharacters) & LCase(EnglishCharacters)
colFullText = 1
colEng = 2
colChn = 3
colContains = 4
For i = First To Last
a = sh.Cells(i, colFullText).Value
txtEnglish = ""
txtChinese = ""
For k = 1 To Len(a)
If InStr(EnglishCharacters, Mid(a, k, 1)) Then
txtEnglish = txtEnglish & Mid(a, k, 1)
Else
txtChinese = txtChinese & Mid(a, k, 1)
End If
Next
sh.Cells(i, colEng).Value = txtEnglish
sh.Cells(i, colChn).Value = txtChinese
Result = 0
If txtEnglish <> "" Then Result = Result + 1
If txtChinese <> "" Then Result = Result + 10
Select Case Result
Case 1
Contains = "ENG"
Case 10
Contains = "CHN"
Case 11
Contains = "BOTH"
Case Else
Contains = ""
End Select
sh.Cells(i, colContains).Value = Contains
Next
End Sub

Display the textboxes results in Excel sheet cells in vb.net

I have two textboxes on a form; one hold the word and the other one holds its numeric value that is calculated based on what the user types. I have a sub that separates each sentence and displays the total for each sentence in Excel. This is the output that being generated from the vb.net code which is listed below. All the words are in A column and all the values in B column. How do I modify the code so it inserts each sentence and its value in two columns? After it reaches the string "Total for sentence 1." it should start inserting the words and its values in columns C & D and so forth.
Sentence one and its value should be displayed in columns A & B, sentence two and its value should be displayed in columns C & D and so on.
Please see the attached image. Text in red is what I currently have and below it is the desired result. Thanks!
My Code in vb.net is:
Private Sub Export_Click(sender As System.Object, e As System.EventArgs) Handles btnCreate.Click
xlWorkBook = xlApp.Workbooks.Add
xlApp.Visible = True
xlWorkSheet = xlWorkBook.Sheets("Sheet1")
Dim columnANum As Integer
Dim columnBNum
columnBNum = 2
columnANum = 2
With xlWorkSheet
.Range("A1").Value = "Word"
For Each cellA As String In txtWord.Text.Split(vbLf)
.Range("A" & columnANum.ToString).Value = cellA
columnANum += 1
Next
.Range("B1").Value = "Value"
For Each cellB As String In txtValue.Text.Split(vbLf)
.Range("B" & columnBNum.ToString).Value = Convert.ToInt32(cellB)
columnBNum += 1
Next
End With
End Sub
EDIT: I made significant changes to this code and tested it; it should do what you're looking for
Sub testExcelColumns()
Dim xlApp As Object = CreateObject("Excel.Application")
Dim xlWorkBook As Object
Dim xlWorkSheet As Object
xlWorkBook = xlApp.Workbooks.Add
xlApp.Visible = True
xlWorkSheet = xlWorkBook.Sheets("Sheet1")
Dim RowNum As Integer = 1
Dim ColNum As Integer = 1
'use .cells(row, column) instead of .range
xlWorkSheet.cells(RowNum, ColNum).Value = "Word"
For Each cellA As String In txtWord.Text.Split(vbLf)
'increment the row
RowNum += 1
'set the value
xlWorkSheet.cells(RowNum, ColNum).value = cellA
If cellA.StartsWith("Total") Then
ColNum += 2
RowNum = 1
xlWorkSheet.cells(RowNum, ColNum).Value = "Word"
End If
Next
'increment to the second column and first row
ColNum = 2
RowNum = 1
'set title
xlWorkSheet.cells(RowNum, ColNum).Value = "Value"
For Each cellB As String In txtValue.Text.Split(vbLf)
'increment the row
RowNum += 1
'set the value
xlWorkSheet.cells(RowNum, ColNum).value = cellB
'get value of cell to the left
Dim t As String = xlWorkSheet.cells(RowNum, ColNum).offset(0, -1).value
If Not t Is Nothing AndAlso t.StartsWith("Total") Then
ColNum += 2
RowNum = 1
xlWorkSheet.cells(RowNum, ColNum).Value = "Value"
End If
Next
End Sub
Try using
Dim RowNum as Integer = 1
Dim ColNum as Integer = 1
use .cells instead of .range
xlWorkSheet.Cells(RowNum, ColNum).value = "Word"
xlWorkSheet.Cells(RowNum, ColNum).value = "Value"
update the row and column as needed
RowNum += 1
ColNum += 1