This should be an easy one for folks. Google's got nothing except content farms linking to one blurb, and that's written in broken English. So let's get this cleared up here where it'll be entombed for all time.
What's the trailing ampersand on VB hexadecimal numbers for? I've read it forces conversion to an Int32 on the chance VB wants to try and store as an Int16. That makes sense to me. But the part I didn't get from the blurb was to always use the trailing ampersand for bitmasks, flags, enums, etc. Apparantly, it has something to do with overriding VB's fetish for using signed numbers for things internally, which can lead to weird results in comparisons.
So to get easy points, what are the rules for VB.Net hexadecimal numbers, with and without the trailing ampersand? Please include the specific usage in the case of bitmasks/flags and such, and how one would also use it to force signed vs. unsigned.
No C# please :)
Vb.net will regard "&h"-notation hex constants in the range from 0x80000000-0xFFFFFFFF as negative numbers unless the type is explicitly specified as UInt32, Int64, or UInt64. Such behavior might be understandable if the numbers were written with precisely eight digits following the "&", but for some reason I cannot fathom, vb.net will behave that way even if the numbers are written with leading zeroes. In present versions of VB, one may force the number to be evaluated correctly by using a suffix of "&" suffix (Int64), "L" (Int64), "UL" (UInt64), or "UI" (UInt32). In earlier versions of VB, the "problem range" was 0x8000-0xFFFF, and the only way to force numbers in that range to be evaluated correctly (as a 32-bit integer, which was then called a "Long") was a trailing ampersand.
Visual Basic has the concept of Type Characters. These can be used to modify variable declarations and literals, although I'd not recommend using them in variable declarations - most developers are more familiar these days with As. E.g. the following declarations are equivalent:
Dim X&
Dim X As Long
But personally, I find the second more readable. If I saw the first, I'd actually have to go visit the link above, or use Intellisense, to work out what the variable is (not good if looking at the code on paper).
Related
I'm trying to parse string to decimal in vb.net which could contain dot or comma, for ex. '5000.00', '5000,00' (actually for Belgium and Niederlands).
Code for decimal with dot:
Decimal.TryParse(amountStr, amountVal)
Code for decimal with comma:
Decimal.TryParse(amountStr, NumberStyles.AllowDecimalPoint, CultureInfo.CreateSpecificCulture("nl-BE"), amountVal)
Is it possible to combine these into one code without replacing comma in string?
Is it possible to combine these into one code without replacing comma in string?
String-replacement is the "usual" solution to this problem. A slightly more elegant alternative would be to check if the string contains a . or a , and then provide the "correct" CultureInfo to TryParse:
Dim isBelgianFormat As Boolean = amountStr.Contains(",")
Dim ci As CultureInfo = If(isBelgianFormat,
CultureInfo.GetCultureInfo("nl-BE"),
CultureInfo.InvariantCulture)
...Decimal.TryParse(amountStr, NumberStyles.AllowDecimalPoint, ci, amountVal)...
This will also allow you to "fine-tune" your guessing logic by replacing the first line with a more complicated algorithm. (For example, this "simple" solution will fail if your users use thousands separators, i.e., if you want to correctly "guess" the value of both 500.000,00 and 500,000.00.)
That having been said, you can make your code more complicated to cover these cases as well, but how do you want to treat, for example, 500.000 or 500,000? Is it half a million or 500?
Thus, I urge you to reconsider your requirements. Especially when parsing monetary values, failing with a helpful error message is often preferable to guessing what the user might have meant.
Edit/Update:
Thank you all for responding. I understand I was being too vague, but wasn't sure if posting naked lines of code would be useful in this case.
In my .vb file I have a pulldown control with its validation values as:
TempUnit.DataSource = {"°C", "°F", "°R", "K"}
...which is stored in a variable:
Dim unit As String = TempUnit.SelectedItem.ToString
...which gets passed into a function along with other variables:
Function xxx(..., ByVal unitT As String) As Double
... which finally calls the .fs file and gets evaluated using:
let tempConv t u =
match u with
|"°C" -> t * 9.0 / 5.0 + 32.0
|"°R" -> t - 459.67
|"K" -> t * 9.0 / 5.0 - 459.67
|_ -> t
If any temperature unit other than Kelvin is selected, the match fails and defaults to the else case (which is Fahrenheit in this context). I ended up bypassing the degree symbol entirely by evaluating the substring instead:
Dim unit As String = TempUnit.SelectedItem.ToString.Substring(1)
The program is working again, but I have no idea what I changed, if anything, to make the string match stop working. The first thing I tried was to copy/paste from one file to other to ensure they were identical strings, in addition to trying other symbols, but to no avail. The degree symbol is what caught my attention, but then I checked the pressure units and found the exact same issue with the micro prefix.
Thank you, Hans Passant, I had unicode in mind as a possible solution, but it didn't seem like an easy fix in the heat of the moment. I appreciate your link.
Original Post:
I have a VB program referencing a function stored in an F# library file whose arguments include unit of measure strings containing special characters (e.g. "°C" "µBar").
The strings are identical in the .vb and .fs files; and there was no issue until the F# library file stopped recognizing the Alt-Code characters for reasons unbeknownst to me.
The program works as intended if I remove the offending Alt-Code character from the string definitions in the F# and VB files.
What would cause a match to fail between two identical strings that happen to contain an Alt-Code character?
What is the proper way to handle Alt-Code characters in F# (and VB for that matter)?
The µ glyph is a bit infamous. Unicode has two codepoints that look like that: U+03BC = "Greek small letter Mu" and U+00B5 = "Micro sign". One is a letter in the Greek alphabet, the other is a symbol that often appears in math and units.
Compare μ and µ. Looks almost identical in most fonts (you can see the difference with Segoe UI) and very easily fools the human eye. Typographers insist they are not the same, particularly if they are Greek I'd imagine. Nor does a computer, the problem you are surely dealing with.
Copy/paste or re-type to fix. The Charmap.exe applet in Windows is very handy to get this right.
I am using VBA in Ms Access environment, to handle long string (memo field storing HTML originally).
After positioning by Instr(), I put the position into Mid(vStr,vStartPos,vEndPos-vStartPos+1) to extract the string, but the output doesn't match. I have already carefully checked this in immediate windows, as well as NotePad++. What I can say is Instr() and NotePad++ have given the same counting result, while Mid() is different. Mid()'s result are former than Instr()'s in some cases, and latter in other cases. I don't know the reason, and can just believe Mid() use different mechanism or have defeative (surprised!) in handling long string mixed with single-byte and bi-byte chars (but this is common in the world, and meet no problem before), and possibly some special characters.
I believe I need to custom-make a Mid() function. Any idea how to do it effectively and efficiently?
Thanks all for your reply. After I created a custom Mid() by RegEx and find that the problem has no change, I have found out the silly mistake I made. The Instr() and Mid() have no problem, but the string has been carelessly modified between them. So this case should be closed now.
Visual Basic 2010 (Express). I can best give this by example...
If I take a string from a textbox and assign it to an integer variable, I'm under the impression that you're supposed to use CInt to explicitly convert the contents to an integer.
intMyCount = CInt(txtUserInput.Text)
However, if I don't do that, it still seems to work. Similarly, if I have an integer and concatenate it into a label's text property, it still works:
lblResults.Text = intMyCount & " number of times."
rather than using intMyCount.ToString.
Why does it work? Is VB doing implicit conversions when possible? Are there examples where not explicitly converting with .ToString or using CInt would cause unexpected results?
This is done using late-binding, and it's dangerous because if the conversion ever fails (and there's lots of cases where your first example could fail) it ends up in an exception at runtime. To get the compiler to enforce safer casting, turn Option Strict On.
Additionally, most of the time you don't want to use CInt() to convert your string to int. Instead, prefer Integer.Parse() or Integer.TryParse().
Some languages handle string concatenation easily like this for the non-casting to string. Some also handle non-casting to numeric types to do calculations. Some languages don't handle it at all. However as a best-practice, I would always cast the variable to the type you want to avoid issues with improper input types.
I set the culture to Hungarian language, and Chr() seems to be broken.
System.Threading.Thread.CurrentThread.CurrentCulture = "hu-US"
System.Threading.Thread.CurrentThread.CurrentUICulture = "hu-US"
Chr(254)
This returns "ţ" when it should be "þ"
However, Asc("ţ") returns 116.
This: Asc(Chr(254)) returns 116.
Why would Asc() and Chr() be different?
I checked and the 'wide' functions do work correctly: ascw(chrw(254)) = 254
Chr(254) interprets the argument in a system dependent way, by looking at the System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage property. See the MSDN article about Chr. You can check whether that value is what you expect. "hu-US" (the hungarian locale as used in the US) might do something strange there.
As a side-note, Asc() has no promise about the used codepage in its current documentation (it was there until 3.0).
Generally I would stick to the unicode variants (ending on -W) if at all possible or use the Encoding class to explicitly specify the conversions.
My best guess is that your Windows tries to represent Chr(254)="ţ" as a combined letter, where the first letter is Chr(116)="t" and the second ("¸" or something like that) cannot be returned because Chr() only returns one letter.
Unicode text should not be handled character-by-character.
It sounds like you need to set the code page for the current thread -- the current culture shouldn't have any effect on Asc and Chr.
Both the Chr docs and the Asc docs have this line:
The returned character depends on the code page for the current thread, which is contained in the ANSICodePage property of the TextInfo class. TextInfo.ANSICodePage can be obtained by specifying System.Globalization.CultureInfo.CurrentCulture.TextInfo.ANSICodePage.
I have seen several problems in VBA on the Mac where characters over 127 and some control characters are not treated properly.
This includes paragraph marks (especially in text copied from the internet or scanned), "¥", and "Ω".
They cannot always be searched for, cannot be used in file names - though they could in the past, and when tested, come up as another ascii number. I have had to write algorithms to change these when files open, as they often look like they are the right character, but then crash some of my macros when they act strangely. The character will look and act right when I save the file, but may be changed when it is reopened.
I will eventually try to switch to unicode, but I am not sure if that will help this issue.
This may not be the issue that you are observing, but I would not rule out isolated problems with certain characters like this. I have sent notes to MS about this in the past but have received no joy.
If you cannot find another solution and the character looks correct when you type it in, then I recommend using a macro snippet like the one below, which I run when updating tables. You of course have to setup theRange as the area you are looking at. A whole file can take a while.
For aChar = 1 To theRange.Characters.count
theRange.Characters(aChar).Select
If Asc(Selection.Text) = 95 And Selection.Text <> "_" Then Selection.TypeText "Ω"
Next aChar