I have a requirement to create codes from numbers.
Ex . If we define
A as 1
B as 2
...
J as 9
K as 0
And if a cell has value 499 then the equivalent code "DJJ" should be returned.
First, find the character associated with the number '1' in the ASCII table:
=CHAR(1)
This will give you the character associated with ASCII code 1. Now find the code # for A, and then add that to your result:
=CODE("A")
This will give you the ASCII code associated with the letter "A". If you test it out, you will see that there is a specific ordering to the ASCII table. It goes through lowercase letters alphabetically, numbers in order, and capitals alphabetically (with special characters thrown in everywhere in a specific fashion). This ordering allows you to find the letters of the alphabet which come after "A", simply by adding 1, 2, etc - ie:
=CHAR(A1+CODE("A")-1)
This would give you the character associated with a number found in A1, starting at the point where the "A" character rests on the ASCII table.
Finally, assume that A1 holds a 3 digit number. To put the above into a cohesive formula, we just need to apply it 3 times, once for each character in your word. We can do this with the LEFT, MID, and RIGHT functions, as follows:
=CHAR(LEFT(A1)+CODE("A")-1) & CHAR(MID(A1,2,1)+CODE("A")-1) & CHAR(RIGHT(A1)+CODE("A")-1)
This first takes the leftmost character found in A1 (say, the number 5), and adds it to the ASCII code for the letter "A". It then returns the character which is 4 places to the right of "A" in the ASCII table [5 - 1 + CODE("A")]. Then it does this for the 2nd character found in A1 (say, the number 6). Then it does this for the rightmost character in A1 (say, the number 0).
There is no error checking in this method; it assumes A1 always holds a 3 digit number, formatted without decimals.
Note that this method makes 0 = to A. I'll leave it to you to decide if you want to shift all numbers to the right so that 1 = A and 0 = K.
Related
Im having some trouble combining two formulas in an if statement. I have a range of 6 columns which may contain a string with a length of 7, this string always starts with a letter followed by two random numbers (the rest of the string is random letter and numbers)
Im interested in finding every 7len string that starts with a letter followed by numbers in position 2 and 3. If the criteria are met the row is marked with a 1.
What I have counts every string with a lenght of 7
=IF(AND(LEN(J2)=7,(ISERR(LEFT(J2,1)*1))),1,0)
If you have Excel 365 you can use this formula:
=LET(
lengthOf7,LEN(A2)=7,
firstLetter,NOT(ISNUMBER(LEFT(A2,1)*1)),
secondThirdNumber,ISNUMBER(MID(A2,2,2)*1),
AND(lengthOf7,firstLetter,secondThirdNumber)
)
It checks all your conditions and "names" them to be more readable.
If you don't have Excel 365 then you can use it like this:
=AND((LEN(A2)=7), NOT(ISNUMBER(LEFT(A2,1)*1), ISNUMBER(MID(A2,2,2)*1))
You could use FILTERXML() to validate the string value:
Formula in B1:
=NOT(ISERROR(FILTERXML("<t><s>"&UPPER(A1)&"</s></t>","//s[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','')*0=0][substring(.,1,1)*0!=0][substring(.,2,2)*0=0][string-length()=7]")))
Where:
"<t><s>"&UPPER(A1)&"</s></t>" - Creates a valid xml-string using the input from A1 in uppercase;
[translate(.,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','')*0=0] - Checks if when all uppercase letters are removed, the remainder multiplied by zero equals zero. This validates only letters and numbers across the input;
[substring(.,1,1)*0!=0] - Validates that the first character in the string is not equal to zero when multiplied by zero (thus being a letter);
[substring(.,2,2)*0=0] - Validates that the substring from the 2nd character with a length of two equals zero when multiplied by zero (thus being numeric);
[string-length()=7] - Validates that the total length of the node equals seven.
If you have ms365, you could actually also use REDUCE() to mimic the above and be less verbose:
=AND(ISNUMBER(REDUCE(UPPER(A1),CHAR(SEQUENCE(24,,65)),LAMBDA(a,b,SUBSTITUTE(a,b,"")))*1),ISERROR(LEFT(A1)*1),ISNUMBER(MID(A1,2,2)*1),LEN(A1)=7)
In this case the recursive SUBSTITUTE() will replace all uppercase letters with an empty string in order to make sure that the remainder is numeric. The other nested AND() parameters are rather self-explainatory.
Note: WAAR and ONWAAR are the Dutch equivalent to TRUE and FALSE.
try this:
=IF(AND(LEN(A1)=7,OR(AND(CODE(MID(A1,1,1))>=65,CODE(MID(A1,1,1))<=90),AND(CODE(MID(A1,1,1))>=97,CODE(MID(A1,1,1))<=122)),CODE(MID(A1,2,1))>47,CODE(MID(A1,2,1))<58,CODE(MID(A1,3,1))>47,CODE(MID(A1,3,1))<58),1,0)
=IF(LEFT(A2,3)="ABC","DEF"),RIGHT(A2,LEN(A2)-3),IF(LEFT(A2,2)="GH"),RIGHT(A2,LEN(A2)-2)
As this does not work, below is what I am attempting to accomplish and an example of it.
Essentially I am trying to remove the first few letters off of a SKU #. However the amount of letters before the SKU can vary and there is letters at the end of the SKU which I do not want removed.
Example:
AB12345
CDE54321XY
Z123
With a result of:
12345
54321XY
123
My knowledge and use of VBA is almost non-existent so I have not tried to do anything with that as I believe the line I have above could work with minor tweaking though I may be wrong.
It's not as good as a regular expression, and since there are only 10 digits, it turns out not too long. The below is an array formula (entered with Ctrl+Shift+Enter):
=MID(A1,MIN(IFERROR(SEARCH({0,1,2,3,4,5,6,7,8,9},A1),9^99)),LEN(A1))
The formula will give an error (#VALUE!) if there are no numbers. It basically looks for the position of a digit in the string and finds the smallest one. For the first example, SEARCH gets the positions: #VALUE!, 3 (1 is at position 3), 4 (2 is at position 4), 5, 6, 7, #VALUE!, #VALUE!, #VALUE!, #VALUE!. The smallest being 3 (I'm using IFERROR and a big number --9^99-- so it ignores the #VALUE!), the MID will take all characters as from the 3rd character inclusive.
For example
1234567 would become 1234567X
12345678 Would stay the same
1234 would stay the same
123456789 Would stay the same
But would need to do this to approximately 20 strings of numbers but only want the X added to those with exactly 7 characters and to leave the others unchanged.
=A1&if(len(A1)=7,"X","")
Where A1 is the string you're checking
Quite simply - copy in A1, then check if length is 7. If it is, add an X. If not, add nothing.
You can use this formula:
=IF(LEN(A1)=7;CONCAT(A1;"X");A1)
You are telling Excel to check if the lenght of a cell in characters is equal to 7 (first parameter, LEN(A1) =7).
If the test condition is true the result will be a concatenation between the cell and the string "X" (second parameter, CONCAT(A1;"X") ).
If the test condition is false, the result will be equal to the cell value (no changes will be made, third parameter, A1))
I have 2 columns. A and B. In column B, I have values like XXDDSSSSS, the important thing here that X can appear 1 time or n number of times but it will always be followed by a number. i.e., VD32lasjdflsak or VDS34dfsadfllo. I want to populate Column A from Column B so that it has all letters from beginning till when the first letter appears i.e., in first example column A should have VD and in next example column A should have VDS
Not as cool as Aggregate, but does the trick!
=LEFT(B1,MIN(FIND({0,1,2,3,4,5,6,7,8,9},B1&"0123456789"))-1)
Try,
=LEFT(A2, AGGREGATE(15, 6, ROW($1:$9)/(CODE(MID(A2, ROW($1:$9), 1))<65), 1)-1)
The position is hard-coded as 1 through 9. This could be adjusted with INDIRECT to 1 through the length of the string if that is insufficient.
I have personal ID's in reports I have to find in one cell. Too bad the string in the cell which hides this ID can be anything, the ID can be at the beginning, the end, anywhere, but it is there.
The only thing I know is the pattern "space,letter,letter,number,number,number,number,number,number,space". Jike DB544345
I was looking for the correct word for this "mask", but couldn't find an answer. Thank you for your help.
As the comments are numerous I have created a minimal example that might represent what the OP is dealing with:
A1: 123456789 DB544345 asdfg asdfghjk
A2: creating dummy data is a DB544345 pain
A3: DB5443456 and soething else
parsed a copy of that in ColumnB with Text To Columns (with space as the delimiter) then applied:
=IFERROR(IF(AND(LEN(B1)=8,CODE(LEFT(B1))>64,CODE(LEFT(B1))<91,CODE(MID(B1,2,1))>64,CODE(MID(B1,2,1))<91,ISNUMBER(RIGHT(B1,6)*1),RIGHT(B1,6)*1>99999),B1,""),"")
to K1, copied this across to P1 and then K1:P1 down.
A concise "built-in function only" solution to a problem such as this requires a bit of tinkering as many attempts will dead-end or need workarounds due to deficiencies and quirks in the built-in Excel formulas. I much prefer single cell formulas because they minimally affect the general spreadsheet structure. However, due to the limitations listed above, complex single cell solutions often come at the cost of being rather long and cumbersome (this answer is somehow still only two lines on my formula bar in Excel). I came back to your question and cobbled together a formula that can (as far as I have tested) extract the first occurrence of this pattern with a single cell formula. This is an array formula (Ctrl+Shift+Enter instead of Enter) that assumes your data is in A2. This rough formula returns the first 8 characters if no match is found and throws #REF if the string is shorter than 10 characters.
=MID(A2,MIN(IF(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9))),1)=" ",IF(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+9,1)=" ",IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))>64,IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))<91,IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))>64,IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))<91,IF(IFERROR(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+3,6)*1>99999,FALSE),ROW(INDIRECT("A1:A"&(LEN(A2)-9)))))))))))+1,8)
Let me try to break this down at least on a high level. We are splitting the main text into every possible ten character chunk so that we can test each one using the suggestion of #pnuts to verify the Unicode values of the first two characters and run an ISNUMBER check on the rest of the string. This first block recurs throughout my formula. It generates a list of numbers from 1 to n-9 where n is the length of our main text string.
ROW(INDIRECT("A1:A"&(LEN(A2)-9)))
Let's assume our string is 40 characters long and replace the above formula with {1...31}. Using this number sequence generation we can check if characters 1 to 31 are spaces:
IF(MID(A2,{1...31},1)=" "
Then we can check if characters 10 to 40 are spaces:
IF(MID(A2,{1...31}+9,1)=" "
Then we can check if characters 2 to 32 are capital letters:
IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))>64,
IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+1,1))<91
Then we can check if characters 3 to 33 are capital letters:
IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))>64,
IF(CODE(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+2,1))<91
Then we can check if the strings of characters 4 to 9, 5 to 10, ..., 33 to 38, 34 to 39 are six-digit numbers:
IF(IFERROR(MID(A2,ROW(INDIRECT("A1:A"&(LEN(A2)-9)))+3,6)*1>99999,FALSE)
If all conditions are TRUE, that 10 digit chunk test will return the index of its first character in the string via another instance of the original array {1...31}. Otherwise it returns nothing. We take the Min of all return indexes and then use the Mid function to grab the 8 digit string determined by the aforementioned minimum index:
=MID(A2,MIN(matching index list)+1,8)
I think this will work, if we assume that the SPACE at the beginning and end are merely to differentiate the ID from the rest of the string; hence would not be present if the ID were at the beginning or end of the string. This formula is case insensitive. If case sensitivity is required, we could do character code comparisons.
=LOOKUP(2,1/((LEFT(myArr,2)>="AA")*(LEFT(myArr,2)<="ZZ")*(LEN(myArr)=8)*ISNUMBER(-RIGHT(myArr,6))),myArr)
Where myArr refers to:
=TRIM(MID(SUBSTITUTE(TRIM(Sheet2!A1)," ",REPT(" ",99)),(ROW(INDIRECT("1:10"))-1)*99+1,99))
If myArr is initially defined with the cursor in B1, referring to A1 as shown, it will adjust to refer to the cell one column to the left of the cell in which the Name appears.
The 10 in 1:10 is the maximum number of words in the string -- can be adjusted if required.