4

I am currently converting vb and vb.net to c# but have an issue. I would strongly like not to use the visualbasic dlls in the converted code and have been doing this fine so far.

But this code

Dim x as Double    'this was error saying it was integer
x = Val("1 23 45 x 6")  ''#x is  12345
x = Val("1..23")    ''#x is 1.23
x = Val("1 1,,,,,2,2..3") ''#x is 1122.3

Does not work the same as vb6 even with using "Val" from the visualbasic.conversion.dll Is there anyone that has solved this to work the same? A c# solution would be best.

djv
  • 15,168
  • 7
  • 48
  • 72
Aditya Om
  • 206
  • 1
  • 4
  • 8
  • 15
    How can x be 1.23 when it's declared to be an integer? – Jon Skeet Dec 01 '10 at 15:21
  • 2
    It's one of those fractional integers, those are all the fad now... – SWeko Dec 01 '10 at 15:25
  • 3
    Personally I think that function is insane. If a German (non programmer) enters "1,23" he won't be happy with 123 as a result instead of 1.23 – CodesInChaos Dec 01 '10 at 15:35
  • @Code - on a german system, it's smart enough to know that , rather than . is the decimal point. – Joel Coehoorn Dec 01 '10 at 15:39
  • 1
    @Joel: According to the documentation it isn't smart enough: *"The `Val` function recognizes only the period (.) as a valid decimal separator."* http://msdn.microsoft.com/en-us/library/k7beh1x9.aspx – LukeH Dec 01 '10 at 15:41
  • @Joel even if it were that smart it would create evil traps. For example I have a German windows, but as a programmer I'm trained to use `.`, so it would silently fail for me. IMO it's better to think about what input values you expect and show an error on anything unexpected. – CodesInChaos Dec 01 '10 at 15:43
  • sorry, not integer - in simplifing the code I made a typeo – Aditya Om Dec 01 '10 at 15:48

6 Answers6

7

None of the above seemed to satisfy my needs, so I wrote the following:

public static Double Val(string value)
{
    String result = String.Empty;
    foreach (char c in value)
    {
        if (Char.IsNumber(c) || (c.Equals('.') && result.Count(x => x.Equals('.')) == 0))
            result += c;
        else if (!c.Equals(' '))
            return String.IsNullOrEmpty(result) ? 0 : Convert.ToDouble(result);
    }
    return String.IsNullOrEmpty(result) ? 0 : Convert.ToDouble(result);
}

Results of the test data:

"0 1 5.2123 123.123. 1 a" returns 15.21233123

" 1 5.2123 123a" returns 15.21233123

"a1 5.2123 123.123. 1 a" returns 0

"" returns 0

Reuben Mallaby
  • 5,740
  • 4
  • 47
  • 45
ericosg
  • 4,926
  • 4
  • 37
  • 59
  • 1
    A small addition would be to allow for negative numbers too. I.e. c.Equals('-') – RooiWillie Nov 15 '22 at 10:50
  • To add negative numbers, first line in if becomes `if (result.Length == 0 && c.Equals('-') ) result += c;`, original `if` becomes `else if` and add or clause in return: `return string.IsNullOrEmpty(result) || result == "-" ? 0 ...`. – mike Jan 18 '23 at 18:03
5

I know nothing of this VisualBasic.Conversion.dll (and neither does google), but the Microsoft.VisualBasic namespace (in Microsoft.VisualBasic.dll) is part of the core framework and perfectly fine and acceptable to use from C#. There are other nice gems in there as well (ie TextFieldParser), but this should have the exact Val() implementation you need.

If this is the library you've already tried and it doesn't seem right, then I'd go take another look at the unit tests on it.

Outside of this, the accepted ways in C# for converting strings to integers are int.Parse(), int.TryParse(), and Convert.ToInt32(). But, like it or not, the Val() function from the Microsoft.VisualBasic.dll library is the closest match you're going to find for your code's existing behavior.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • I understand and thanks - I was wishing for Val() to match completely the vb6 Val, but perhaps close will be good. – Aditya Om Dec 01 '10 at 15:50
  • 1
    +1 Don't let prejudice harm your productivity. See also discussion [here](http://stackoverflow.com/questions/226517/is-the-microsoft-visualbasic-namespace-true-net-code) – MarkJ Dec 01 '10 at 17:43
1

There is no exact equivalent of vb6 val function in C#. But this function can be used by using Microsoft.VisualBasic namespace in C#.

To use val() function in C# add Microsoft.VisualBasic namespace and use following code:

Conversion.Val("09sdf");
ArunPratap
  • 4,816
  • 7
  • 25
  • 43
1

You could use the Convert static class. It's pretty close to Val() but you need to specify the convert to type. It's in the System namespace.

E.g.:

int x = Convert.ToInt32("23");
int y = Convert.ToDouble("23.342");

http://msdn.microsoft.com/en-us/library/system.convert(v=vs.71).aspx

thkala
  • 84,049
  • 23
  • 157
  • 201
Johnny B
  • 21
  • 1
  • 1
    It's not as close a match as you may think because `Val("") = 0` but `Convert.ToDouble("")` throws an exception – Matt Wilko Feb 11 '15 at 17:03
0

From your examples it could look similar to this. But since I don't know the VB val specification it might not work on all strings correctly.

Decimal ParseNumerString(string s)
{
    Decimal value=0;
    Decimal multiplier=1;
    bool decimalPart=false;
    foreach(char c in s)
    {
      if(IsDigit(c))
      {
        int i=ParseDigit(c);
        if(!decimalPart)
        {
          value=value*10+i;
        }
        else
        {
         muliplier/=10;
         value=value+multiplier*i;
        }
      if(c=='.')
        decimapPart=true;
      }
      return value;
}

This is pseudocode you need to implement parse digit and is digit yourself(trivial). I chose Decimal as internal representation because that way I don't get strange rounding errors in the fractional part.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
0

Had the same issue, started with @ericosg 's answer, then realized I needed Negative Numbers and Scientific Notation

namespace VB6
{
    public class Helper
    {
     public static double Val(object value)
        {
            double returnVal = 0;
            string sToParse = value == null ? "" : value.ToString();
            string result = string.Empty;
            string num = string.Empty; //In the case of scientific notation e.g. 3e5 = 300000
            foreach (char c in sToParse)
            {
                if (result.Length == 0 && c.Equals('-'))//negative numbers
                    result += c;
                else if (Char.IsNumber(c) || (c.Equals('.') && result.Count(x => x.Equals('.')) == 0)) 
                    result += c;
                else if ((c.Equals('e') || c.Equals('E')) && num.Length == 0 && result.Length != 0) //scientific notation
                {
                    num = result;
                    result = string.Empty;
                }
                else if (!c.Equals(' '))
                {
                    break;
                }
            }

            if (num.Length > 0)
            {
                //scientific notation
                double fSignificantFigures = string.IsNullOrEmpty(result) || result == "-" ? 1 : Math.Pow(10, Convert.ToDouble(result));
                returnVal = num == "-" ? 0 : Convert.ToDouble(num) * fSignificantFigures;
            }
            else
            {
                returnVal = string.IsNullOrEmpty(result) || result == "-" ? 0 : Convert.ToDouble(result);
            }

            return returnVal;
            
        }
   }
}
mike
  • 2,149
  • 20
  • 29