Why does AllowExponent makes Decimal.Parse fail to parse normal numbers? - vb.net

I tried these
Dim a = Decimal.Parse("0.00001", System.Globalization.NumberStyles.Any)
Dim c = Decimal.Parse("0.00001")
Dim cb = Decimal.Parse("0.00001", System.Globalization.NumberStyles.AllowExponent)
The first code works.
The second line works.
The third line doesn't work.
It seems that if I do not mention the numberstyles, the numberstyles default to something. Default to what?
It basically allow parsing normal number (".00001"). However, that ability is turned off if System.Globalization.NumberStyles.AllowExponent is specified as parameter.
Why is this happening?
What is the default value of NumberStyles if we use the normal overload of Decimal.parse, without additional parameters?

You wouldn't write a number with exponent other than a whole number. See my comment above.
Dim cb = Decimal.Parse("1e-5", System.Globalization.NumberStyles.AllowExponent)
MessageBox.Show(cb.ToString)
Dim ab = Decimal.Parse("1e-5", System.Globalization.NumberStyles.Any)
MessageBox.Show(ab.ToString)
Both message boxes show .00001.

I just want to add that per Parsing decimal in scientific notation
System.Globalization.NumberStyles.AllowExponent
doesn't allow putting decimals.
It's probably unituitive.
Hence,
cb = Decimal.Parse("0.00001", System.Globalization.NumberStyles.AllowExponent)
will throw error because the parser cannot parse .
I have no idea why it's designed that way. So how are we going to parse 4.5e10, for example.
You need other options. AllowExponent seems to do exactly that. Allow Exponent and that's it.

Related

VB.Net -" console.write(Format((87.20 \ 43.60))) " returning result of 1 not 2, why?

The below line of code is returning as a 1 instead of a 2, for reasons I can't comprehend.
console.write(Format((87.20 \ 43.60)))
Surely this should return the result of 2 but I've checked in another environment and it returns a can anyone tell me why?
I have tried putting the code into a second environment but the result was the same I don't understand why it is returning 1 instead of 2, can anyone enlighten me?
Thanks for the help but found the answer.
Decimals are converted to Long before Integer division and due to this are subject to banker's rounding, multiplying both numbers by a 100 before the operation resolves the issue.
Source of information:
Learn Microsoft - VB.Net - \ Operator - Remarks
Thanks,
While I am glad you resolved your own question, I did want to provide an alternative.
When you use the integer division operator, you do not have control as to how the rounding should occur. Whereas if you do a floating-point division operator you can keep the precision and then use one of the built-in Math class methods (documentation) to specify how the number should round.
Take a look at this example:
Dim result = 87.20 / 43.60
Dim roundUp = Math.Ceiling(result)
Dim roundDown = Math.Floor(result)
Dim bankersRounding = Math.Round(result)
Fiddle: https://dotnetfiddle.net/LZEMXV
Because in your example you are using Console.Write (which treats the data as a String) you do not need to cast the value to an Integer data type. However, if you needed the value as an Integer, any one of those variables outside result can be safely converted to an Integer using the Parse method (documentation).

Import txt file data and store it in Multidimensioanl array in Vb.net

Sorry if the problem is so basic, I'm a bit used to python not VB.net
I'm trying to read text file data (numbers) and store it in array/list
# Sample of text
1.30e+03,1.30e+03,1.30e+03
5.4600e+02,2.7700e+02,2.8000e+02
# PS: I can control the output of the numbers to have delimiter = ',' or space between numbers, whatever is easier to import
I wrote the following code to read string data and store it. yet, I don't know how to have a multidimensional array (2D or 3D) instead of 1D string (e.g. for the text above, it would be 2x3 array)
' Import Data
Comp_path = FinalPath & "Components_colors.txt"
reader = New StreamReader(Comp_path)
Dim W As String = ""
Dim wArray(10) As String
Dim i As Integer = 0
Do Until reader.Peek = -1
W = reader.ReadLine()
wArray(i) = W
i += 1
Loop
Moreover, I don't know the length of the text file, so I can't determine the length of the array like I did in the code above for the string wArray
For a file like this, you should turn to NuGet for a dedicated CSV parser. There are parsers built into .NET you could also use, but pulling one off of NuGet will also let you parse the values directly into something other than a string.
But if you really don't want to do that you can start with this (assuming Option Infer):
Public Function ImportData(filePath As String) As IEnumerable(Of Double())
Dim lines = File.ReadLines(filePath)
Return lines.Select(Function(line) line.Split(",").Select(AddressOf Double.Parse).ToArray())
End Function
And use it like this:
Comp_path = FinalPath & "Components_colors.txt"
Dim result = ImportData(Comp_path)
Note this code doesn't actually do any meaningful work yet. It doesn't even read the file. What it does is give you an object (result) that you can use with a For Each loop or linq operations. It will read the file in a just-in-time way, parsing out the data for each line as it goes. If you want an array (or List, which you should use in .Net more often), you can append a ToList() call to the end:
Comp_path = FinalPath & "Components_colors.txt"
Dim result = ImportData(Comp_path).ToList()
But you should try to avoid doing that it. It's much less efficient in terms of memory use. The first sample will only ever need to keep one line of the file in memory at a time. Adding ToArray() or ToList() needs to load the entire file.
Some more notes:
Many newer dynamic platforms like Python don't actually use real arrays in the formal computer science sense (fixed block of contiguous memory). Rather, they use collections, and just call them arrays. .Net has collections, too, but when you declare an array, you get an array. This has nice benefits for performance, but if you don't know you want that or how to take advantage of it you're probably better off asking for a generic List most of the time instead.
Thanks to cultural/internationalization issues, parsing numeric (or date) values to string and back again is much slower and more error-prone than you've believed in the past, especially coming from a dynamic platform. It is slow on these other platforms, too, but they want you to pretend it isn't. The first introduction to a strongly-typed platform like .Net can feel stifling in this area, but once you understand the performance and and reliability benefits, you won't want to go back.
In strongly-typed platforms it is very important to understand the data types you are working with at every level of an expression. Otherwise, building and reading statements like the Return line in my answer will be way more difficult and frustrating than it needs to be.

Sabre Web/ .NET - Special Characters In SabreCommandLLSRQ Response Not Handed Properly

I'm using VB.NET to consume Sabre Web Services, primarily using SabreCommandLLSRQ to send native Sabre commands. Sending special characters without any special encoding works fine, but when I try to manipulate any response that contain the Cross of Lorraine using the Response element of SabreCommandLLSRS all of the Cross of Lorraine chars are missing if I display my string in a MsgBox or try to manipulate it.
If I push that string into my clipboard and view it in Notepad++, the characters are there but they seem to be encoded improperly - they come through as something like "‡". I'm pretty new to unicode encoding so that's all a bit above my head.
I've tried using the Replace method of String Builder to change those characters to something visible no avail - anyone have a way around this issue?
Strangely, the other special characters (e.g. "¤") seem to come through just fine.
This section in Dev Studio includes references to special character hex codes:
https://developer.sabre.com/docs/read/soap_apis/management/utility/Send_Sabre_Command
Does this help?
This is a pain in the behind due to the invisible characters.
String replace does work you just need to make sure you capture the invisible character after the Â
Simply in the SabreCommandSend function before you send the string to Sabre put something like the below.
Hopefully this should copy and paste straight out including the invisible character.
if (tempCommand.Contains("‡"))
{
tempCommand = tempCommand.Replace("‡", "Â");
}
I figured out how to get this to work, but its not pretty so if anyone has a better way to do it, I'm all ears.
I couldn't figure out what char to use to do the simple string Replace method, so instead I'm casting the string to a byte array, iterating through the array and replacing any strange characters I find, recasting the byte array into a raw string and doing the string replace on that:
Imports System.Text
Dim byteArray() As Byte = System.Text.Encoding.ASCII.GetBytes(sabreResponse)
For i = 0 To byteArray.Length - 1
If byteArray(i) = 63 Then 'this is a question mark char
byteArray(i) = 94 'caret that doesn't exist in native Sabre
End If
Next
MyClass.respString = System.Text.ASCIIEncoding.ASCII.GetString(byteArray)
MyClass.respString = MyClass.respString.Replace("^", "¥")
For whatever reason, the string replace method works after I swap out the offending byte with a dummy character but not before.

CDec doesn't return the correct value

I make code that multiply all values of a DatagridView column. The code is working, but there's a problem. In particular, I've added this:
Return CDec(x.Cells("Quote").Value.ToString.Replace(",", "."))
That returns me the split value, for example, if I would have:
2,7 the correct value to return is: 2.7, but the code returns 27 and this is strange. I performed some trying, and if I delete the CDec like:
Return x.Cells("Quote").Value.ToString.Replace(",", ".")
The value returned is correct, but I've a contrast with this function:
Private Function MultiplyDecimals(ByVal sender As Decimal()) As Decimal
Dim Result As Decimal
If Not sender Is Nothing AndAlso Not sender.Length = 0 Then
Result = sender.Aggregate(Function(a, b) a * b)
End If
Return Result
End Function
That returns me 0 if I delete "As Decimal". So what's wrong?
UPDATE with possible solution:
Dim bles = x.Cells("Quote").Value.ToString.Replace(",", ".")
Dim key = Convert.ToDecimal(bles)
MessageBox.Show(key)
Return CDec(key)
Since it looks like you are also trying to manually convert from a different culture, you should use the .NET methods for this, rather than roll your own. You have two conversions going on: From one cultural number system to another and from string to a numeric type.
To convert a string like "2,7" which might be a French or Italian value:
Dim str As String = "2,7"
Dim decVal As Decimal
If Decimal.TryParse(str, NumberStyles.AllowDecimalPoint,
New CultureInfo("it-IT"), decVal) Then
' decVal has the value
Else
' Parse failed
End If
or:
Dim cult As New CultureInfo("fr-FR")
If Decimal.TryParse(str, NumberStyles.AllowDecimalPoint,
cult, decVal) Then ...
This can often work, but you might get an exception depending on the content:
Dim decVal As Decimal
Dim cult As New CultureInfo("fr-FR")
decVal = Convert.ToDecimal(str, cult)
Console.WriteLine(decVal.ToString)
Note: I am guessing at the culture of the data. Based on your recent, related question Google indicates "Nazione" is Italian, but data from/about Algeria might well be French Algerian.
CDec, like most of the legacy VB functions, is only equipped to work with the active culture settings. So, it will seem like it is "broken" in some cases:
Console.WriteLine(CDec("2.7")) ' --> 2.7D US/Can
Console.WriteLine(CDec("2,7")) ' --> 27D
Console.WriteLine(CDec("2,,7")) ' --> 27D
On a machine using French or Italian culture, the opposite will happen: "2.7" will come out 27, "2,7" to 2.7D, but "2,,7" will probably crash just like "2..7" would in the US/Can.
The reason for this behavior is that in US/Can, a comma looks like noise and CDec ignores it. A string with a single decimal-dot will convert, but a string with 2 is invalid. It would be the reverse for French where the comma is used: any number of dots look like noise, and only single decimal-comma format will parse.
It is all part of the reason no one included CDec in the solution: It is sub-optimal for any sort of cultural conversions. Manually removing or replacing decimal markers is even less optimal when there are methods designed to do that only when needed.
Since you have a string value, try Decimal.Parse() instead of CDec().
If that doesn't give you the result you expect, then either you're not handling the string that you think you are (in which case, try logging the exact string to a text file or similar so you can see exactly what you have), or the PC's culture settings are not what you think they are (it may be set to a culture that uses the comma, rather than a period, as the decimal separator), in which case try one of the Decimal.Parse() overloads that allows you to specify the culture, or perhaps even just remove the call to .Replace().

Convert String to int16

I faced a "ridiculous" problem.
I was trying to convert a string to int16 (I am forced to do it in int16 and not in int32/integer).
My first thought was to try:
convertedVal = Convert.ToInt16(newVal)
which thrown an exception: Value was either too large or too small for UInt16.
But my string was "10", so it was between the minValue and the maxValue.
I solved my problem using :
convertedVal = Int16.Parse(newVal) 'TryParse works also
Although I solved my problem I haven't understand what I did wrong.
Could somebody explain to me why this happened?
Thanks for your time
This usually happens if there is an extra space on the string, so better Trim it
convertedVal = Convert.ToInt16(newVal.Trim())
Both methods should be the same according to the MSDN page
Using the ToInt16(String) method is equivalent to passing value to the Int16.Parse(String) method. value is interpreted by using the formatting conventions of the current thread culture.
Where do you get this string?
If it comes from user input I wouldn't trust much that he/she types a correct int16 value to use a Convert or Parse method.
using TryParse leads to a more robust code.
Dim result as Short
Dim newVal as String = "10 sadaas"
if Int16.TryParse(newVal, result) = False then
result = 0
end if