I am trying to write a helper script for a colleague that will automatically open up all .doc(x) files in a directory, find any and all chinese characters, set their Font, save and close.
I already have a working version of this script. The file opening/saving/closing part is handled in Python/win32com and works fine. My big point of contention is still the VBA macro.
I know there is a regex (\p{Han}) that should be able to catch all Chinese characters, but this does not seem to work in VBA. Similarly, I have tried using Unicode Ranges and Chr(W). Nothing so far produced any output, let alone correct output.
Out of frustration, I made one last ditch attempt and simply inverted the search paramters. This is how it is now:
Sub FindReplace_zh(Rng As Range)
With Rng.Find
Do While .Execute(FindText:="[!A-ZÄÖÜa-zäöü0-9><_ ^11^13§$²³%#&/\+-]", MatchWildcards:=True)
If Rng.Font.Bold = True And Rng.Font.Name Like "Arial*" Then
Rng.Font.Name = "SimHei"
ElseIf Rng.Font.Bold = False And Rng.Font.Name Like "Arial*" Then
Rng.Font.Name = "SimSun"
End If
Rng.Collapse 0
Loop
End With
End Sub
AT LEAST THIS WORKS, but its far from elegant and still produces some undesired output.
I have yet to understand how I can substitute "[!A-ZÄÖÜa-zäöü0-9><_ ^11^13§$²³%#&/+-]" with a variable, or most anything else. Many characters are not covered by this regex, such as "(", ")" etc., but adding them (even escaped with ) will result in runtime errors in VBA.
I found a lot of tutorials and questions dealing with removing or inserting text, but my specific case of finding text and then changing the font, while leaving everything else untouched, seems rather specific.
Fun fact:
I had to add ^11 and ^13 to the regex list, as not including them would lead to the Macro inserting new linebreaks in random positions of the .doc
EDIT:
New try with comment:
Dim searchPattern As String
searchPattern = "[" & ChrW(&H2E80) & "-" & ChrW(&HFFED) & "]{1,}"
With Rng.Find
Do While .Execute(FindText:=searchPattern, MatchWildcards:=True)
Invalid operation on final line!
I also would not have concatinated a string like this. I am not sure how VBA parses this, but apprently not the way we hoped.
EDIT2: FIX
Removing "{1,}" from searchPattern did it. Now it works exactly as I expected it to :)
searchPattern = "[" & ChrW(&H2E80) & "-" & ChrW(&HFFED) & "]"
It is possible to find the value of characters that cannot be represented in the VBIDE by pasting them into an empty Word document and then using VBA to print the AscW values of each character in the text you wish to investigate. You can then use ChrW in VBA to reassemble the text in a VBA friendly way.
From
pinyin.info/news/2016/…
You can use the find string "[⺀-■]{1,}" to find any Chinese character. However as you have noted when you paste this text into the VBA IDE you get [?-?]{1,} because VBA uses UTD-8 as its character set. (I think).
The following code
Public Sub PrintCharacterValues()
Dim myIndex As Long
With ActiveDocument.Paragraphs(1).Range
For myIndex = 1 To 8
Debug.Print .Characters(myIndex), AscW(.Characters(myIndex)), Hex(AscW(.Characters(myIndex)))
Next
End With
End Sub
Gives the output of
" 34 22
[ 91 5B
? 11904 2E80
- 45 2D
? -19 FFED
] 93 5D
" 34 22
160 A0
Thus you can get the critical section of the find string as
"[" & ChrW(&H2£80) & "-" & ChrW(&HFFED) &"]"
Related
I've created a set of macro files in Microsoft Word's VBA as a sort of a CAT tool (CAT = https://en.wikipedia.org/wiki/Computer-assisted_translation). The problem is that there are cases where I display the text needed to be translated and the user needs to input text in his own language. That might include some special chars, like "ăîâșț/ĂÎÂȘȚ", or even quotes or brackets. Is there any way to use those in some InputBox function? Or, at least, some way to let the user input the text he needs in some TextBox or something?... Or how should I approach this?... Maybe UTF-8 support would be what I need? Or?... Any help would be appreciated!...
I've tried Microsoft Word's vba function InputBox. I'm also thinking if, maybe, I would be able to create my own InputBox, with my conditions on it, I might be able to have one that accepts those chars too, or all the chars into some string variable... Here is something someone on StackOverflow says:
Is it possible to create an 'input box' in VBA that can take a text selection with multiple lines as an input? (I'm referring to gizlmo's answer...)
Here are 3 lines of code that contain that (although it's more of a how to question, not a debugging question, so those are not really needed...)
MsgBox ("Ziua " & Str(ziua) & " - " & titlurien(ziua))
titluales = InputBox("Titlul original: " & titlurien(ziua), "Ziua: " & Str(ziua) & ", Rapsodia Realitatilor " & monthname(lunanecesara) & Str(annecesar))
titluriro(ziua) = titluales
I expect the output to be exactly what he typed, whether it's quotes, brackets or special characters (like "ăîâșț"/"ĂÎÂȘȚ")...
A VBA InputBox will take any character typed or pasted into it. The characters available to type depends on the Language version of Windows and Office that the end user has installed.
Below is a test I just made with your example character string "ăîâșț/ĂÎÂȘȚ"
SpecialCharInput()
Dim str As String
str = InputBox("Enter you text", "Special Test Input Box")
Debug.Print str
End Sub
On my English language system, the only trouble it had was with the upper and lower case "ȘȚ" Turkish characters. By trouble I mean it turned those characters into question marks "??" in the result string. I'm sure though, if my system supported the Turkish language that those characters would be recognized and outputted properly.
I've been searching for two days to solve my issue but so far nothing.
There are many (Very many) vba excel tools developed where I work and our regional settings in PC-s determine comma as decimal separator but reports and data downloaded from our systems have dot as decimal separator. In these tools, when needed we just have set UseSystemSeparators = False then DecimalSeparators = "." and at the end of the macro reverted back.
Now new people have been getting windows 10 pcs and some of the tools run into errors. I got a Win10 pcs from IT to test and found out that no matter how I set in Excel settings VBA Macro uses PC regional settings while on the sheet it still uses what is determined in Excel settings. Same file, same test in my win7 pc and if set then both on sheet and vba macro use local application settings.
Does anyone know what is the reason and how it could be fixed? I can figure many workarounds but all of these mean that the tools need to be re-coded and there are just so many of these that I still keep finding out new tools used and what were developed before I joined the company in March. Changing all ~300 PC-s regional setting is not an option because it needs to be comma as decimal separator normally.
Edit: just to make it bit more clear I'll add some code:
Sub test()
Application.UseSystemSeparators = False
Application.DecimalSeparator = "."
variable = "10.1"
MsgBox CDbl(variable)
End Sub
Under Windows 7 - no problem. The variable containing a string can be converted.
Under Windows 10 - Run-time error, Type mismatch. Both PCs have "," as system separator. The funny thing is that when I change "10.1" to "10,1" then that works on both PC-s. Settings for both PC-s are same. System uses "," as separator and Excel is set to use ".".
This answer is based on your system (default) DecimalSeparator being a comma (,) and ThousandsSeparator being a point (.) - using Windows 10
Explanation:
I've done a little testing and found that the following functions only change the DecimalSeparator within Excel, not within VBA:
Application.UseSystemSeparators = False
Application.DecimalSeparator = "."
Application.ThousandsSeparator = ","
This means that when you change the DecimalSeparator by using these lines of code, it will simply update the values in your workbooks to be displayed in the format you are specifying. For example if your system format is:
100.000.000,99
Then the lines of code above would convert the values to:
100,000,000.99
However, when you run the code above and try to use a string that uses the non-system format for the DecimalSeparator then VBA will not recognise it.
Example:
(Where Application.DecimalSeparator = "," when Application.UseSystemSeparators = True)
Sub TestSeparator()
Application.UseSystemSeparators = False
Application.DecimalSeparator = "."
Application.ThousandsSeparator = ","
Debug.Print CDbl("100.99")
End Sub
This code will return 10099, not the expected double of 100,99 (in your system format) because VBA does not see the DecimalSeparator of "." as a DecimalSeparator.
Solution:
When referencing doubles within VBA you will need to always use the computer's system separators for thousands and decimals. If the doubles are being imported as strings you will need to use Replace to convert the string into a format that uses system separators.
Solution Example:
(Where Application.DecimalSeparator = "," when Application.UseSystemSeparators = True)
If you have the string of "100,000,000.99" in cell A1 and use the following code:
CDbl(Range("A1").Value)
It will produce a "Type mismatch" error. However if you convert this into a string that uses your system separators then no error will be given. You will need to use two Replace functions though, one to remove the ThousandsSeparators and one to convert the DecimalSeparators to your system ones:
CDbl(Replace(Replace(Range("A1").Value, ",", ""), ".", ",")
Perhaps this:
Set ws = ThisWorkbook.Worksheets("Name of Worksheet")
ws.Cells.Replace What:="", Replacement:="", LookAt:=xlPart, _ SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=True, ReplaceFormat:=True
Set ws = Nothing
I've been lurking here for a while but this is my first post so let me know if I need to change something. Anyways, here goes:
I'm trying to create a macro that will add hyperlinks to cells in a worksheet. The problem is that after running the macro, I notice that the folder location of my spreadsheet has been prepended to the address that I specified. Is there something I need to do in order to indicate that this is a webpage and not a local file? Excerpt from the macro is below.
Dim IGQ As Range
Dim IGQno As String
Dim IGQno1 As String
For Each IGQ In Range("A2:A10") 'Actual range is much larger
IGQno = IGQ.Value
IGQno1 = Left(IGQ, 1)
Sheets("Cameron DCDA").Hyperlinks.Add Anchor:=IGQ, _
Address:="""http://xxxx""&IGQno1&""xxx""&IGQno&""xxxxx""" 'It's a company website so they probably don't want me to share it
Next
The result is that a hyperlink is created for each cell but it links to file:///C:\Users\John.Doe\Documents\"http://xxxx"&IGQno1&"xxx"&IGQno&"xxxxx"
I've tried using fewer quotation marks in the address since it seems like overkill but I get the compile error "Expected: end of statement"
Do you guys have any suggestions?
Too many quotes
Address:="http://xxxx " & IGQno1 & "xxx" & IGQno & "xxxxx"
Also - be sure to leave a space before your & otherwise it will be interpreted as a variable type suffix:
What are possible suffixes after variable name in VBA?
I'm trying to identify a cell has line breaks(not the menu bar cell option, actual multiple lines through alt+enter), and extract each line separatedely
I have tried both
InStr(str, "\n") < 0
and
Split(str, "\n")
But doesn't seem to be working
VBA is not C# ("\n"). Line breaks you'll find on: vbCr or vbLf or vbCrLf constants.
For further information, please see:
vbCr
vbLf
vbCrLf
[EDIT]
Points to Mat's Mug answer! I forgot about vbNewLine constant.
There are no escape sequences in VBA. Use the built-in vbNewLine constant instead for the equivalent:
hasLineBreaks = InStr(str, vbNewLine) > 0
Per MSDN, vbNewline returns a Platform-specific new line character; whichever is appropriate for current platform, that is:
Chr(13) + Chr(10) [on Windows] or, on the Macintosh, Chr(13)
So you don't need to work with ASCII character codes, or even with their respective built-in constants.
Except Excel will strip CR chars from cell and shape contents, and this has nothing to do with VBA (the CR chars would be stripped all the same and "\n" wouldn't work for correctly reading that Excel data in C#, Javascript, or Python either) and everything to do with the context of where the string came from.
To read "line breaks" in a string with the CR chars stripped, you need to look for line feed chars in the string (vbLf).
But if you systematically treat the line feed character as a line ending, you'll eventually run into problems (esp.cross-platform), because ASCII 10 all by itself isn't an actual line break on either platform, and you'll find ASCII 13 characters in strings you thought you had stripped line breaks from, and they'll still properly line-break on a Mac, but not on Windows.
Consider either:
Split(str, Chr(10))
or
Split(str, Chr(13))
You may need to try both if the data has been imported from external source.
I am needing to insert a formula in using vba coding.
at the moment the line of code is
=IF(
AND(
Compliance="No",
OR(
Delivery <> "",
C31 <> ""
)
),
"Please Delete Compliance Data",
IF(
AND(
E11="",
E13="",
E23="",
E25="",
E26="",
E28="",
E30="",
E31=""),
VLOOKUP(C15,'Extrapolated RV Calculator'!B:S,18,0),
"Please complete form / SC request"
)
)"
It seems to error out on the text portions inside the code.
Any help would be appreciated.
Here are four ways to use quotation marks inside strings in VBA:
Replace "" with Chr$(34). 34 is the ASCII code for quotation marks
Use String(2,Chr$(34)) to make double quotes
Use two double quotation marks for every one (per Tim's comment)
Replace two double quotation marks with a different method, like ISBLANK for worksheet functions.
None of these is better. I usually use two double quotation marks to escape them. But sometimes I get so many quotation marks together that it's hard to read and maintain, so I'll use a different method. Here's an example:
Dim aFormula(1 To 5) As String
aFormula(1) = "=IF(AND(Compliance=""No"",OR(Delivery<>" & String(2, Chr$(34))
aFormula(2) = ",C31<>" & String(2, Chr$(34)) & ") ),"
aFormula(3) = Chr$(34) & "Please Delete Compliance Data" & Chr$(34)
aFormula(4) = ",IF(AND(ISBLANK(E11),ISBLANK(E13),ISBLANK(E23),ISBLANK(E25),ISBLANK(E26),ISBLANK(E28),ISBLANK(E30),ISBLANK(E31)),"
aFormula(5) = "VLOOKUP(C15,'Extrapolated RV Calculator'!B:S,18,0),""Please complete form / SC request""))"
Sheet1.Range("R13").Formula = Join(aFormula, vbNullString)
To empower you for the future I strongly recommend you do the following when you want to use functionality in Excel in your VBA code that you are not acquainted with yet.
Go to the developer menu and press the record macro button.
Now fill in a formula in a cell, Clear a cells content by pressing delete and clearing a cells content by going into the cell and deleting all the characters and press enter.
Now stop the macro. And go to the VBA window. See how the code is structured to accomplish these things.
Apply this also whenever you want to do other things to get a good idea of what you can use to get the results you want without having to browse around on the internet for ages!
Also watch the local variables in the locals window or Debug.Print the string you try to build to see hwat it looks so far