Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Val() function in VBScript

Status
Not open for further replies.

ESquared

Programmer
Dec 23, 2003
6,129
US
The Val() function may or may not work for you in VBScript. In any case, it has some dangers as it can fail with a Type Mismatch error in some situations where it should not.

CInt() doesn't work if the string you're trying to work has non-numeric characters in it.

Some people write their own Val() function to step through a string character by character and pull out the numbers. I've also seen solutions where people used regular expressions to remove non-number characters and then throw CInt() at the number.

But an alternate way is to simply use server-side javascript:

Code:
<SCRIPT language="javascript" runat="server">
function VBValInt(theexpression) {
   var thevalue = parseInt(theexpression)
   if (isNaN(thevalue)) thevalue = 0
   return thevalue
}

function VBValFloat(theexpression) {
   var thevalue = parseFloat(theexpression)
   if (isNaN(thevalue)) thevalue = 0
   return thevalue
}
</SCRIPT>
This does not go inside the usual <% %> enclosing marks.

This method is probably faster than a custom function, and can handle more expressions than simply removing non-number characters.

Now in your ASPs you can simply replace val with one of these functions like so!

Code:
Response.Write VBValInt(Request.QueryString("value"))
You can use this method of calling server-side javascript in any situation where you have a function that you like from javascript. For example, if you validate some controls on a form in the client's browser using javascript, why write it in VBScript all over again? Just copy the exact function to the server and validate it. This makes development faster and more robust.

I have tested the Int function but not the Float function.

Erik

PS It's considered good practice to write client-side script in javascript. This ensures compatibility with non-Microsoft browsers, and helps separate server script from client script in your mind. Of course, here I am telling you to break that rule. But sometimes it makes sense.
 
Alright, I have made some modifications to my benchmark script and tried several alternatives. I'll list the results first and the code second and last will be a finding that I ran into when modifying the benchmark script for this exercise.

From what I see in the results it looks like the Javascript method is consistently a bit faster, with the VBScript RegExp method being clearly the worst possible method. However this is a measurement over 10,000 sets of 4 calls each and does not take into account any overhead in calling another script engine when switching languages. I have a couple ideas on how to measure that as well, but nothing reliable.
Results:
Code:
Parse Number Benchmark
Date: 1/27/2007 9:26:25 AM
Number of runs: 4
Loops Per Run: 10000
Total Elapsed: 24.48438 seconds

Method 	Average	Low	High	Run 1	Run 2	Run 3	Run 4
Method #3	0.215	0.188	0.234	0.219	0.188	0.219	0.234	Javascript ParseInt
Method #5	0.227	0.203	0.250	0.250	0.234	0.203	0.219	Perlscript Regex
Method #1	0.246	0.141	0.344	0.281	0.219	0.344	0.141	VBScript Loop
Method #4	0.344	0.281	0.422	0.313	0.422	0.281	0.359	Perlscript Loop
Method #7	0.871	0.828	0.906	0.828	0.875	0.875	0.906	Python Regex
Method #6	0.871	0.797	0.953	0.797	0.953	0.906	0.828	Python Loop
Method #2	2.938	1.953	3.281	3.266	3.250	3.281	1.953	VBScript Regex

Functions
Code:
Function vbsInt(expression)
	vbsInt = 0
	Dim t, s
	s = Trim(expression)
	For t = 1 To Len(expression)
		If IsNumeric(Left(s,t)) Then
			vbsInt = CInt(Left(s,t))
		Else
			Exit Function
		End If
	Next
End Function

Function vbsInt2(expression)
	Dim regex, matches
	Set regex = new RegExp
	regex.Pattern = "^\s*(\d+)"
	Set matches = regex.Execute(expression)
	If matches.Count > 0 Then
		vbsIn2t = matches(0).Value
	Else
		vbsInt2 = 0
	End If
End Function

%>
<script runat="server" language="JavaScript">
function jsInt(theexpression) {
   var thevalue = parseInt(theexpression)
   if (isNaN(thevalue)) thevalue = 0
   return thevalue
}
</script>
<script runat="server" language="Python">
def pyInt(expression):
	num = 0
	for c in expression:
		if '0' <= c <= '9':
			num = num * 10 + ord(c) - ord('0')
		elif c == ' ' and num == 0:
			num = 0
		else:
			return num
	return num

</script>
<script runat="server" language="Python">
import re
def pyInt2(expression):
	p = re.compile("^(?:\s*)\d+")
	m = p.match(expression)
	if m:
		return m.group()
	return 0
</script>
<script runat="server" language="PerlScript">
sub psInt(){
	my $t = 0;
	foreach my $d (split(//, shift())) {
		if(int($d) eq $d){
			$t = $t * 10 + $d;
		}
		elsif($t eq 0 && $d eq ' '){}
		else{
			return $t;
		}
	}
	return $t;
}
</script>
<script runat="server" language="PerlScript">
sub psInt2($expression){
	my($text) = @_;
	$text =~ /^\s*(\d+)/;
	return int($1);
}
</script>

Values for Test Runs
Code:
TEST_NUMBER(0) = "12345"
TEST_NUMBER(1) = "   12345 something"
TEST_NUMBER(2) = "12345.345"
TEST_NUMBER(3) = "blah blah 12345"

Finding:
I found out that you cannot use GetRef to get a direct reference to a function in the runat block, even if that function was already evaluated prior to the ASP section being run. I was forced to stick to an Execute() call to call the functions, which will cause some overhead.

Benchmark Changes
If the old benchmark thread is active I'll try to change the generic script, update that thread, and package this whole thing together (generic script and this specific one) and upload to the same location as the current live version.
if anyone is interested in a GetRef version I can supply notes on the minor changes required to switch to that.

-T

 
Whoops, should have noted something:

For those that haven't seen the benchmark before, the times posted are for the total time to run the number of loops for each set + function. So in this case the times (in seconds) are for calling each function 10,000 times. Something worth noting here is that if I scale this back to 100 loops it only takes .25 seconds to run all 2800 function calls (4 runs, 100 loops, 7 functions) and that is including the overhead of the necessary 2800 calls to Execute() to run those functions.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top