Sunday, 5 March 2023

More on converting a currency string to a real (introducing STRINDEX)

As an astute comment pointed out, the code that I presented the other day for converting a currency string (like $1,234.56) to a real would have problems if the string represented an amount greater than one million. I was going to write that Priority has no STRPOS function; if it had one, then locating the commas and removing them would be simpler than my laborious code. 

I have just discovered that whilst there is no STRPOS function, there is a function called STRINDEX that is more or less the same. So if there was a string like '$1,234,567.89', it could be turned into a string that can be turned into a real with the following code.

SUB 850; /* :ASTRING will be something like '$1,234,567.89'; */ :ASTRING = SUBSTR (:ASTRING, 2, 24); /* Lose the leading dollar */ :AREAL = ''; :RESULT = 0E9; :POS = 0; LABEL 851; SELECT STRINDEX (:ASTRING, ',', 1) INTO :POS FROM DUMMY; GOTO 852 WHERE :POS = 0; :AREAL = STRCAT (:AREAL, SUBSTR (:ASTRING, 1, :POS - 1)); :ASTRING = SUBSTR (:ASTRING, :POS + 1, 24); LOOP 851; LABEL 852; :AREAL = STRCAT (:AREAL, :ASTRING); :RESULT = ATOR (:AREAL); RETURN;

Note that the $ sign is liable to be converted into the procedure's name (see here). Fortunately, in my case, the currency sign is ₪ which is ignored by the preprocessor.

Now that I know about the existance of the function STRINDEX, I am liable to use it whenever necessary. I doubt that I am going to update existing code but I will use it in the future. 

It turns out that STRINDEX exists only from version 21 onwards - and of course, the client who needs this code is running version 20.

1 comment:

  1. Indeed it's frustrating how limited the string-handling functions are in Priority. If you can't use this method then you could try the approach that I considered:
    Use STRPIECE to get the bits of the string between the commas.

    The goal here is just to remove all commas and then try converting what remains. You might be tempted to loop until STRPIECE returns nothing, but it seems to me that if you had a string with two commas in the middle you'd get an empty string for that chunk even though you're not at the end yet, and you'd stop too early.
    While a string with two commas wouldn't really be a valid number, we need to allow for such a situation. I'd be inclined to build a string from the output of STRPIECE (one chunk at a time) while calculating the length of the original string implied by the number of times around the loop, and comparing that to the length of the original string in order to decide to stop. Maybe complex but properly abstracted and not limited to a particular string length. Also should work properly for Indian numbers.

    For example if you had (after removing the initial character - and I would do that only after verifying it not to be a digit) 12,34,,567.89 that is 13 characters. After 12 you would set your count to 3 (2+1 for the assumed trailing comma), after 34 it would be 3+2+1, after blank 6+0+1, after 567.89 7+6+1 which is more than 13 so you must have finished. In parallel with that counting obviously you concatenate those chunks to 1234567.89 and you finish by trying to convert that after checking with ISFLOAT as you did before.

    Hope that works at I think it would.

    ReplyDelete