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 bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Split a number into separate digits 2

Status
Not open for further replies.

monkeymagic2222

Technical User
May 13, 2002
78
GB
Hi,

Is there a way to seperate each digit in a string containing a number. Say for example I had: 123456789012, i'd like each number in a variable so:

num1 = 1
num2 = 2 ...
num12 = 2

The number will always be 12 digits long but the 12th character may sometimes be an "X".

Thanks.
 
Do you want to split it into an array?

Or just have 12 lines like this:
num1 = Mid(TheString, 1, 1)
num2 = Mid(TheString, 2, 1)
num3 = Mid(TheString, 3, 1)
...
num12 = Mid(TheString, 12, 1)
 
look at Right(), Left() functions...

left(mystring, 1) gives 1
left(mystring, 2) gives 2
and so on...

-DNG

 
Thanks both.

I think Mid is the answer, the problem I had with Left() and Right() is they include numbers up to that point. eg.

num1 = left(thestring, 1)
num2 = left(thestring, 2)
num3 = left(thestring, 3)

num1 = 1
num2 = 12
num3 = 123

Thankyou both.
 
I would scratch the string manipulation functions and go Regular Expressions. Seeing a few dozen Mid()'s in a row to populate var's really seems poor to me. You can do the complete task in a few lines and populate a array very easily in a much better manner

 
What about this - this can account for any length of number. Can't remember the syntax for a dynamic array but 60 slots should be sufficient...

<%

Dim MyArray(60)
TheNumber=123456789012

For i=1 to Len(TheNumber)
MyArray(i)=MID(TheNumber,i,1)
Next

%>
 
Following onpnt's comments.. A Regular Expression method to return a collection of numbers from a string:
Code:
set reMatchNums = New RegExp
reMatchNums.Global = True
reMatchNums.Pattern = "[\d]"

set oMatches = reMatchNums.Execute("1234567890")

to use the collection, just iterate through it e.g.:
Code:
For Each oMatch in oMatches
  response.write(oMatch.Value & "<br />")
Next

Apart from being neater, simpler, more efficient and also scalable to almost any length of number, it has the added bonus of only reading digits - even if the string contains other stuff, such as decimal points or alpha characters.

A smile is worth a thousand kind words. So smile, it's easy! :)
 
Too bad MS couldn't have implemented split the same way perl did: split on "" splits on every character.

Tracy Dryden

Meddle not in the affairs of dragons,
For you are crunchy, and good with mustard. [dragon]
 
Thanks for all your feedback.

The string that is being entered is a 12 character customer reference number. I need to break it down into individual digits so I can multiply each digit by a different multiplier. This will in turn give me something I can validate the 12th character (the check digit) with to see if its a valid customer number. I have so far used a combination of reading each number into an array (as per emozley's post) and then putting the result of multiplying each number into variables. This seems to work although its probably not the best way to do it.
 
i would suggest doing the way damber posted...

good one damber...

-DNG
 
I apologize for lack there of examples and such. I try to get a few minutes here and there over the last few years to post but it always gets cut short.

So...there really should not be much thought put into this one. Honestly! Let's learn the right way and not the way that works ;)

I ran some benchmarks on the functions (using Tarwn's benchmark script as always @ thread333-939632) and the stat's show it.

Here they are
Code:
Tarwn's Basic Benchmark
Date: 1/20/2006 8:49:39 AM
Number of runs: 4
Loops Per Run: 10000
Total Elapsed: 11.49805 seconds

Method    Name    Average    Low    High    Run 1    Run 2    Run 3    Run 4
Method #1	RegEx Method	0.739	0.680	0.834	0.742	0.834	0.701	0.680
Method #2	Mid Method	1.383	1.189	1.488	1.482	1.488	1.371	1.189
As you can see the RegEx method is more efficient in this simply case. There are many things of course not mentioned above in using the collections wen they are created etc. that need to be weighed before saying the stat's are 100% accurate to the application being written also. I can tell you from years of experience they probably will not change much on the testing and changes you may make.

Going farther on using something like a regex object over built in string manipulation functions; don't get sucked into how you write things. You can easily loose all the performance you can pick up in using the right method by simply creating your objects in the wrong place in the script.

Anyhow, if all this is futile and sense that array works for you and future maintenance and usability of functions correctly isn't what you want now then I'm hoping you're not using that predefined array of (60) and dynamically filling it be ReDim Preserve etc.

example
Code:
	Dim MyArray()
	Dim TheNumber : TheNumber = 123456789012
	Dim i : i = 0

	Do While i <= Len(TheNumber)
		ReDim Preserve MyArray(i)
		MyArray(i)=MID(TheNumber,i+1,1)
	i = i + 1
	Loop
didn't test that one so it may not be correct but you get the point..

alright, my minute of getting to have fun is over...:(

 
OK you've convinced me to use a regular expression. I'm new to this but I think (hope even!) i've figured it out for what I need. Because the string may sometimes have an X on the end i've added \w to Pattern. I still need to put each number in a variable so I can multiply it by the relevant multiplier, i'm guessing this is done in the way I have put below (it works) but I may be wrong.

set reMatchNums = New RegExp
reMatchNums.Global = True
reMatchNums.Pattern = "[\d, \w]"

set oMatches = reMatchNums.Execute(TheNumber)

num1 = oMatches.item(0)
num2 = oMatches.item(1)
num3 = oMatches.item(2)
num4 = oMatches.item(3)
num5 = oMatches.item(4)
num6 = oMatches.item(5)
num7 = oMatches.item(6)
num8 = oMatches.item(7)
num9 = oMatches.item(8)
num10 = oMatches.item(9)
num11 = oMatches.item(10)
num12 = oMatches.item(11)
 
you can use this loop:

For Each oMatch in oMatches
response.write(oMatch.Value & "<br />")
Next

instead as sugegsted by damber...

-DNG
 
What exactly are you trying to compare - putting numbers in variables doesn't help you checksum them against something, so what are you doing with the variables - there could be an even easier way... that doesn't duplicate memory usage by copying data from one data structure to another for no reason.

And what do you want to do with the X ? if it is not relevant to the checksum process, why do you want it in the output ?

What are the relevant multipliers ? if you multiply each value by its index or its predecessor, then total - you don't need separate variables (well not as many)..

more info please... ;-)

A smile is worth a thousand kind words. So smile, it's easy! :)
 
OK heres some further information. I'm writing a validation routine to check if a customer reference number (the 12 digit string) is a valid reference number. In something like Excel this is normally done by taking each digit and multiplying it by a specific number. For example if I had a ref number of 123456789012 then I may do the following:

1 x 5
2 x 3
3 x 1 and so on.

The totals from these numbers are added together, divided by 11 and a few other calculations performed. The remainder should match the 12th digit. That would prove it was a valid customer number. Some customer numbers have an X as the 12th digit (I have no idea why, historic reasons within the company!) but an X should basically be treated as a 1.

Hope this sheds a little more light!
 
What are the specific numbers ? Is there a pattern or are they random ? Where do you store these numbers - in an array ?

Not knowing what your algorithm is for determining the validity of the string, I've just put together some rough code that might will do the sum/multiplication (watch out for typo's though..)
Code:
dim aMultipliers : aMultipliers=Array(5,3,1,5,3,1,5,3,1,5,3)
dim iCustNum : iCustNum = "123123123123"
dim reMatchNums : set reMatchNums = New RegExp
dim iCheckSum : iCheckSum = 0

reMatchNums.Global = True
reMatchNums.Pattern = "[\d]"
set oMatches = reMatchNums.Execute(iCustNum)

if oMatches.Count = (Ubound(aMultipliers)+2) then
  for i=0 to (Ubound(aMultipliers))
    iCheckSum = iCheckSum + ( oMatches.item(i) * aMultipliers(i) )
  next
 [COLOR=green]''' Do some other calculations and checks...[/color]
else
  response.write("Invalid Customer Number: Wrong number of digits")
end if

A smile is worth a thousand kind words. So smile, it's easy! :)
 
Thanks damber thats great, I shall give it a try.

The multipliers are always the same, they are 1, 0, 80, 7, 32, 4, 12, 0, 10, 18, 3. The total is then divided by 11 and the remainder of this is subtracted from 11. The end result should match the 12th digit. If there is no remainder, the check digit is 0, if the remainder is 1 then the check digit is an X.
 
Hmm, I thought up another method and decided to follow onpnt's example and use my benchmark script. I did 4 full Checksum functions because splitting the string is only half the battle. Here are my results:
Code:
Checksum Benchmark
Date: 1/21/2006 11:29:53 AM
Number of runs: 4
Loops Per Run: 10000
Total Elapsed: 18.98438 seconds

Method	Name	Average	Low	High	Run 1	Run 2	Run 3	Run 4
Method #2	0.309	0.297	0.344	0.297	0.297	0.344	0.297	Checksum w/ Mid() 2
Method #1	0.418	0.406	0.438	0.406	0.422	0.438	0.406	Checksum w/ Mid()
Method #4	0.465	0.453	0.469	0.453	0.469	0.469	0.469	Checksum w/Mod
Method #3	2.359	2.297	2.391	2.359	2.391	2.391	2.297	Checksum w/Regex

And here are my four methods and the variables I created before them:
Code:
Dim testVal : testVal = "123456789012"
Dim arrMultipliers : arrMultipliers = Array(1,0,80,7,32,4,12,0,10,18,3)

Function Method1()
	Dim m1Array(11)
	Dim m1i, m1Temp

	For m1i = 0 To 11
		m1Array(m1i) = Mid(testVal,m1i+1,1)
	Next

	For m1i = 0 To 10
		m1Temp = m1Temp + m1Array(m1i) * arrMultipliers(m1i)
	Next

	Method1 = (CInt(m1Array(11)) = 11 - (m1Temp Mod 11))
End Function

Function Method2()
	Dim m2i, m2Temp, m2Target

	m2Target = CInt(Right(testVal,1))
	For m2i = 0 To 10
		m2Temp = m2Temp + CInt(Mid(testVal,m2i+1,1)) * arrMultipliers(m2i)
	Next

	Method2 = (m2Target = 11 - (m2Temp Mod 11))
End Function

Function Method3()
	Dim m3Regex, m3Results, m3Result
	Dim m3i, m3Temp
	m3i = 0

	Set m3Regex = New RegExp
	m3Regex.Global = True
	m3Regex.Pattern = "\d"
	Set m3Results = m3Regex.Execute(testVal)
	For Each m3Result In m3Results
		If m3i = 11 Then
			Method3 = (CInt(m3Result) = 11 - (m3Temp Mod 11))
			Exit For
		End If

		m3Temp = m3Temp + CInt(m3Result) * arrMultipliers(m3i)
		m3i = m3i + 1
	Next
End Function

Function Method4()
	Dim m4Temp, m4i, m4Rem
	m4Rem = "." & testVal & "1"

	For m4i = 0 To 11
		m4Rem = m4Rem * 10
		m4Rem = m4Rem - ((m4Rem\10) * 10)
		If m4i = 11 Then
			Method4 = (Fix(m4Rem) = 11 - (m4Temp Mod 11))
			Exit Function
		End If
		m4Temp = m4Temp + Fix(m4Rem) * arrMultipliers(m4i)
	Next
End Function

I have run this twice and got similar results both times. I can only expect that looping through the results collection is the painful part of the regex one. I tried with a For loop with Results.Count and a counter but the results were pretty much inline with what I posted.

Obviously this is just a rough idea of perforamce, as there area numberof external factors that can't be included, such as what else is running, RAM, CPU type, etc. Ithink it will scale, but again we aretalking about very small efficiency numbers.

For an example you can compare my earlier numbers from my Windows desktop (Grendel) to my dying work laptop that can't seem to get under 90% RAM usage:
Code:
[b]Grendel[/b]
AMD 3700+, 2 1GB matched (quality) RAM sticks, SATA HDD, WinXP
Checksum Benchmark
Date: 1/21/2006 11:29:53 AM
Number of runs: 4
Loops Per Run: 10000
Total Elapsed: 18.98438 seconds

Method	Name	Average	Low	High	Run 1	Run 2	Run 3	Run 4
Method #2	0.309	0.297	0.344	0.297	0.297	0.344	0.297	Checksum w/ Mid() 2
Method #1	0.418	0.406	0.438	0.406	0.422	0.438	0.406	Checksum w/ Mid()
Method #4	0.465	0.453	0.469	0.453	0.469	0.469	0.469	Checksum w/Mod
Method #3	2.359	2.297	2.391	2.359	2.391	2.391	2.297	Checksum w/Regex

[b]Dying Work Laptop[/b]
Dell C840 - P4 2.4, 2 generic 256MB sticks, 5400 IDE HDD, Win2k
Checksum Benchmark
Date: 1/21/2006 11:39:32 AM
Number of runs: 4
Loops Per Run: 10000
Total Elapsed: 84.84375 seconds

Method	Name	Average	Low	High	Run 1	Run 2	Run 3	Run 4
Method #2	1.331	1.297	1.367	1.301	1.367	1.297	1.359	Checksum w/ Mid() 2
Method #1	1.507	1.480	1.535	1.535	1.484	1.480	1.527	Checksum w/ Mid()
Method #4	1.560	1.527	1.582	1.559	1.570	1.582	1.527	Checksum w/Mod
Method #3	11.957	11.922	11.996	11.949	11.961	11.996	11.922	Checksum w/Regex

barcode_1.gif
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top