How do I find the last number in a string with excel formulas

Viewed 224

I'm parsing strings in excel, and I need to return everything through the last number. For example:

Input: A00XX
Output: A00

In my case, I know the last number will be between index 3 and 5, so I'm brute-forcing it with:

=LEFT([@Point],
IF(SUM((MID([@Point],5,1)={"0","1","2","3","4","5","6","7","8","9"})+0),5,
    IF(SUM((MID([@Point],4,1)={"0","1","2","3","4","5","6","7","8","9"})+0),4,
        IF(SUM((MID([@Point],3,1)={"0","1","2","3","4","5","6","7","8","9"})+0),3,
))))

Unfortunately, I've run into some edge cases where the numbers extended beyond index 5. Is there a generic way to find the last number in a string using excel formulas?

Note: I've tried =MAX(SEARCH(... but it returns the index of the first number, not the last.

3 Answers

As a starting point: if we know the position of the last number, we can use LEFT to get the string to that point. Suppose that the position is 5:

=LEFT(A1, 5)

But, we don't know the position of the last number. Now, what if the only valid number was 0, and it only appeared once: then we could use FIND to locate the position of the number:

=LEFT(A1, FIND(0, A1))

But, we have more than one valid number. Suppose that we had all the numbers from 0 through 9, but each number could only appear once — then we could use MAX on a FIND array, to tell us which of the numbers is the last one:

=LEFT(A1, MAX(FIND({0,1,2,3,4,5,6,7,8,9}, A1)))

Unfortunately, FIND will throw a #VALUE! error any number doesn't appear, which will then make MAX return the same error. So, we need to fix that with IFERROR:

=LEFT(A1, MAX(IFERROR(FIND({0,1,2,3,4,5,6,7,8,9}, A1), 0)))

However, numbers can appear more than once. As such, we need a method to find the last occurrence of a value in a string (since FIND and SEARCH will, by default, return the first occurrence).

The SUBSTITUTE function has 3 mandatory arguments — Initial String, Value to be Replaced, Value to Replace with — and one Optional argument — the occurrence to replace. Normally, this is omitted, so that all occurrences are replaced. But, if we know how many times a character appears in a string, then we can replace just the last instance with a special/uncommon sub-string to search for.

To count how many times a character appears in a String, just start with the length of the String, then subtract the length when you SUBSTITUTE all copies of that character for Nothing:

=LEN(A1) - LEN(SUBSTITUTE(A1, 0, ""))

This means we can now replace the last occurrence of the character with, for example, ">¦<", and then FIND that:

=FIND(">¦<", SUBSTITUTE(A1, 0, ">¦<", LEN(A1) - LEN(SUBSTITUTE(A1, 0, ""))))

Of course, we want to do this for all the numbers from 0 to 9, and take the MAX value (remembering our IFERROR), so we need to put the Array of values back in:

=MAX(IFERROR(FIND(">¦<", SUBSTITUTE(A1, {0,1,2,3,4,5,6,7,8,9}, ">¦<", LEN(A1) - LEN(SUBSTITUTE(A1, {0,1,2,3,4,5,6,7,8,9}, "")))), 0))

Then, we plug that all back into our initial LEFT function:

=LEFT(A1, MAX(IFERROR(FIND(">¦<", SUBSTITUTE(A1, {0,1,2,3,4,5,6,7,8,9}, ">¦<", LEN(A1) - LEN(SUBSTITUTE(A1, {0,1,2,3,4,5,6,7,8,9}, "")))), 0)))

An alternative, assuming that the length of the string in question will never be more than 9 characters (which seems a safe assumption based on your description):

=LEFT(A1,MATCH(0,0+ISERR(0+MID(A1,{1;2;3;4;5;6;7;8;9},1))))

This, depending on your version of Excel, may or may not require committing with CTRL+SHIFT+ENTER.

Note also that the separator within the array constant {1;2;3;4;5;6;7;8;9} is the semicolon, which, for English-language versions of Excel, represents the row-separator. This may require amending if you are using a non-English-language version.

Of course, we can replace this static constant with a dynamic construction. However, since we are already making the assumption that 9 is an upper limit on the number of characters for the string in question, this would not seem to be necessary.

If you have the newest version of Excel, you can try something like:

=LEFT(D1,
LET(x, SEQUENCE(LEN(D1)),
MAX(IF(ISNUMBER(NUMBERVALUE(MID(D1, SEQUENCE(LEN(D1)), 1))), x))))

For example: enter image description here

Related