2

I have record like this

A                          Result
Hello AP#12/22 Welcome     AP#12
Thanks AP#123-21           AP#123
No problem AP#111          AP#111

So as you can see i need the AP code from the string. It must not contain the - or / part.

Note:

AP code can be of any number of digit

It can appear at the end or start

AP code can be followed by / or - or any other special symbol such as : or any other.

So i need a generalized formula rather than checking for each special character(/, -, :) to get AP code.

I want to achieve this without using VB.

Raj
  • 45
  • 6
  • You should use Regex. See: https://stackoverflow.com/questions/22542834/how-to-use-regular-expressions-regex-in-microsoft-excel-both-in-cell-and-loops – Luuklag Dec 01 '17 at 12:56
  • @Luuklag thx. But i want to do it without using vba if possible. – Raj Dec 01 '17 at 13:00
  • 1
    That should also be possible, using multiple combinations of the Instring, left and right functions. Would be a lot of work though, seeing there are plenty possibile seperators in your case. – Luuklag Dec 01 '17 at 13:07
  • Does it always start with `AP#`? And what is the max amount of numbers that can follow afterwards? – ImaginaryHuman072889 Dec 01 '17 at 13:17
  • @ImaginaryHuman072889 Yes it always starts with AP# but can have as many as 3 digits – Raj Dec 01 '17 at 13:18

2 Answers2

3

Probably not the most efficient solution... but here's a way without VBA: (line break added for readability)

= "AP#"&MID(MID(A1,FIND("AP#",A1)+3,999),1,
  MAX((ISNUMBER(MID(MID(A1,FIND("AP#",A1)+3,999),{1,2,3},1)+0)+0)*{1,2,3}))

EDIT

Slightly better solution:

= MID(A1,FIND("AP#",A1),
  MAX(ISNUMBER(MID(MID(A1,FIND("AP#",A1)+3,999),{1,2,3},1)+0)*{1,2,3})+3)

EDIT (again)

As pointed out in comment, this does not take into account something like AP#1-1. Here is the updated formula that will take this into account:

= MID(A1,FIND("AP#",A1),IFERROR(MATCH(FALSE,
  ISNUMBER(MID(MID(A1,FIND("AP#",A1)+3,3),{1,2,3},1)+0),0),4)+2)

As requested, here is how this formula works. I'll break it down step by step. This is a pretty long explanation but if you just take it one step at a time, I think you should be able to understand the entire formula. I'm going to explain what is going on from the inside out.

FIND("AP#",A1) returns the character index number in A1 where the first instance of AP# appears in A1.

For simplicity, I will refer to FIND("AP#",A1) as <x1> in the next step.

MID(A1,<x1>+3,3) returns the 3 characters in A1 that appear immediately after AP#. It only returns 3 characters because from the original problem, you said that up to 3 numbers can appear after AP#.

(Quick note: Originally I had this part of the formula as MID(A1,<x1>+3,999) but after making this explanation, I realized that 999 could be reduced to 3. 999 would still work, just that 3 is simpler and makes the formula more efficient.)

I will refer to this value MID(A1,<x1>+3,3) as <x2> in the next step.

MID(<x2>,{1,2,3},1) essentially converts <x2> which is a string of 3 characters, to a array of 3 strings, each string 1 character long. In other words, if <x2> is (for example), "1-2", then that means MID(<x2>,{1,2,3},1) is {"1","-","2"}. It is necessary to convert a string of 3 characters to a 1x3 array of single characters in order to individually analyze each character.

I will refer to MID(<x2>,{1,2,3},1) as <x3> in the next step.

<x3>+0 may seem like a simple step but there is a lot going on here. Keep in mind <x3> is still an array of strings, not numbers (even if they look like numbers). The +0 will convert all strings that look like numbers to numbers, and will convert all strings that don't look like numbers to an error value. (In this case, #VALUE!.)

Sticking with our same example, {"1","-","2"}+0 will equal {1,#VALUE!,2}.

I will refer to <x3>+0 as <x4> in the next step.

MATCH(FALSE,ISNUMBER(<x4>),0) returns the first index of <x4> where it is not a number. The idea here is to find the index of the first non-number, and then include everything up to that index (minus one).

Sticking with our same example, MATCH(FALSE,ISNUMBER({1,#VALUE!,2}),0) would return 2, because the 2nd index in {1,#VALUE!,2} is the first index that is not a number.

I will refer to MATCH(FALSE,ISNUMBER(<x4>),0) as <x5> in the next step.

It is possible that all values in <x4> are numbers, in which case <x5> would return an error because it can't find a match for a non-number. IFERROR(<x5>,4) fixes this issue. It returns the value 4 if all values in <x5> are numbers. The reason to return 4 is because we are basically saying that all 3 of the characters following AP# are numbers, so the first index that we aren't considering after AP# is the 4th index.

I will refer to IFERROR(<x5>,4) as <x6> in the next step.

<x6>+2 may seem like a strange calculation, and it is, so I will write it a different way that will make more sense: (<x6>-1)+3

Remember what <x6> represents here: It is the index of the first non-number that appears in the string of 3 characters after AP# . Therefore, <x6>-1 is the number of characters to include after AP#.

Now, why add 3? (<x6>-1)+3 is necessary to include the 3 characters in AP# itself. This will make sense in the next step.

I will refer to <x6>+2 as <x7> in the next step.

MID(A1,FIND(AP#,A1),<x7>) returns a portion of string A1, starting at the A in AP# and spanning <x7> characters. And how large is <x7>? It is however many numbers are in the AP# code, plus 3. (Again, we must add 3 to include the 3 AP# characters themselves in the calculation.)

This is the entire calculation.

Come to think of it, you may want to wrap an IFERROR around the entire calculation to take care of cases where AP# isn't found in the string, e.g. something like:

= IFERROR(MID(A1,FIND("AP#",A1),IFERROR(MATCH(FALSE,
  ISNUMBER(MID(MID(A1,FIND("AP#",A1)+3,3),{1,2,3},1)+0),0),4)+2),"no match")

But really that is your call. I'm not sure if this is necessary.

ImaginaryHuman072889
  • 4,953
  • 7
  • 19
  • 51
  • 1
    it is not working for this example - abc paid by AP#7-679 for jan17. it is returning AP#7-6 instead of AP#7. – Raj Dec 01 '17 at 18:06
  • @Raj Ah, good point. I hadn't thought of this scenario originally. See my answer again, I updated based on this. It should work now. – ImaginaryHuman072889 Dec 01 '17 at 18:19
  • Thnx. its working now i will accept your answer. It would be great if you could explain the logic behind the formula so that i could use it in other work as well. Thanks again. – Raj Dec 02 '17 at 05:50
  • @Raj See my answer again. I edited to explain formula. – ImaginaryHuman072889 Dec 02 '17 at 13:39
2

Consider the following User Defined Function:

Public Function FindAPcode(s As String) As String
    Dim L As Long, CH As String, i As Long, j As Long

    FindAPcode = ""
    L = Len(s)
    If L = 0 Then Exit Function
    j = InStr(1, s, "AP#") + 3
    If j = 3 Then Exit Function
    FindAPcode = "AP#"

    For i = j To L
        CH = Mid(s, i, 1)
        If IsNumeric(CH) Then
            FindAPcode = FindAPcode & CH
        Else
            Exit Function
        End If
     Next i
End Function

enter image description here

User Defined Functions (UDFs) are very easy to install and use:

  1. ALT-F11 brings up the VBE window
  2. ALT-I ALT-M opens a fresh module
  3. paste the stuff in and close the VBE window

If you save the workbook, the UDF will be saved with it. If you are using a version of Excel later then 2003, you must save the file as .xlsm rather than .xlsx

To remove the UDF:

  1. bring up the VBE window as above
  2. clear the code out
  3. close the VBE window

To use the UDF from Excel:

=myfunction(A1)

To learn more about macros in general, see:

http://www.mvps.org/dmcritchie/excel/getstarted.htm

and

http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx

and for specifics on UDFs, see:

http://www.cpearson.com/excel/WritingFunctionsInVBA.aspx

Macros must be enabled for this to work!

Community
  • 1
  • 1
Gary's Student
  • 95,722
  • 10
  • 59
  • 99