Validating a Salesforce Id
Asked Answered
B

12

35

Is there a way to validate a Salesforce ID, maybe using RegEx? They are normally 15 chars or 18 chars but do they follow a pattern that we can use to check that it's a valid id.

Bayberry answered 16/3, 2012 at 18:51 Comment(2)
do you know at least what characters are to be considered valid>?Trichromatism
@BogdanEmilMariesan I don't understand your question. The chars are different for different object records, which is why it's not a straightforward regex I think.Bayberry
F
48

There are two levels of validating salesforce id:

  1. check format using regular expression [a-zA-Z0-9]{15}|[a-zA-Z0-9]{18}
  2. for 18-characted ids you can check the the 3-character checksum: enter image description here

Code examples provided in comments:

Footwork answered 27/3, 2015 at 11:36 Comment(1)
I created a gist based on the info above and it check(sums) out. I'll see myself out. gist.github.com/jeriley/36b29f7c46527af4532aaf092c90dd56Volva
S
30

Something like this should work:

[a-zA-Z0-9]{15,18}

It was suggested that this may be more correct because it prevents Ids with lengths of 16 and 17 characters to be rejected, also we try to match against 18 char length first with 15 length as a fallback:

[a-zA-Z0-9]{18}|[a-zA-Z0-9]{15}
Suzysuzzy answered 16/3, 2012 at 19:5 Comment(7)
It's rather crude, but I like it. :) Thanks! I've +1 your answer.Bayberry
A more compact way to phrase this would be \w{15,18}Hydrastine
In most regex implementations, \w would include _, so the above is not correct.Tonetic
This will only work with 15 characters long IDs. The 3 character suffix is computed from the first 15. If you are not sure, that 18 character long ID have the right suffix, you better chop them off. It is the same, but "15" IDs are not sortable in case insensitive way. Basicaly, you can pass as ID anything that matches [a-zA-Z0-9]{15} or [a-zA-Z0-9]{18} with right suffix. Everything else will fail.Massotherapy
Unfortunately it appears this won't work in all cases. It appears that salesforce does additional validation beyond just the format (15 or 18 digit, alphanumeric), and I've run into cases where I get a string exception when trying to assign a id that matches this regex to an id variable ...Trencher
Won't you need to anchor the Regex pattern to prevent strings greater than length 18 from passing? Like so: ^([a-zA-Z0-9]{15}|[a-zA-Z0-9]{18})$Scientism
Please see zacheusz's detailed answer: https://mcmap.net/q/422918/-validating-a-salesforce-idPerfoliate
I
25

Just use instanceOf to check if the string is an instance of Id.

String s = '1234';
if (s instanceOf Id) System.debug('valid id');
else System.debug('invalid id');
Indiscipline answered 8/12, 2016 at 17:5 Comment(1)
It seems this is NOT foolproof. instanceof returns true for '403E1005-CC70-48B6'.Dietsche
C
12

The easiest way I've come across, is to create a new ID variable and assign a String to it.

ID MyTestID = null;
try {
    MyTestID = MyTestString; }
catch(Exception ex) { }

If MyTestID is null after trying to assign it, the ID was invalid.

Chaisson answered 16/3, 2012 at 19:6 Comment(6)
Is this good practice? I try to avoid try-catch as much as possible (doesn't mean I don't use it well) I always thought try-catches are resource heavy.Member
The reason this is bad practice is that you should NEVER flippantly use try/catch. The reason is that Try/Catch is a very complex operation, causing your code to run for many more cycles on the processor. Of course the time complexity varies based on the language and compiler, however I think we can all safely assume that Apex's version is quite probably horrible.Pickaxe
True, it's costly, but it's also the best way that I could find that works in this case...Chaisson
I agree with the two comments questioning if this is good practice, though I think it is totally fine if you are just going to do it on a single user input for example. It might be slow, but because there is only one run, it will not be a something you would notice.Bestialize
@Member not sure there is a better way, i'm running into this with queries from string input, and the only option is to try catch the query, or try catch the string to an id to validate it, the regex still lets invalid ids through since salesforce appears to do some additional validation above 15 or 18 digit alphanumericTrencher
@Ralph I just thought of another idea which could be worse - try to delete the record and find if its valid. So yes, this would be the most effective wayMember
C
6

This regex has given me the optimal results so far.

\b[a-z0-9]\w{4}0\w{12}|[a-z0-9]\w{4}0\w{9}\b
Celka answered 17/1, 2020 at 13:23 Comment(0)
B
4

You can also check for 15 chars, and then add an extra 3 chars optional, with an expression similar to:

^[a-z0-9]{15}(?:[a-z0-9]{3})?$

on i mode, or not:

^[A-Za-z0-9]{15}(?:[A-Za-z0-9]{3})?$

Demo


If you wish to simplify/modify/explore the expression, it's been explained on the top right panel of regex101.com. If you'd like, you can also watch in this link, how it would match against some sample inputs.


RegEx Circuit

jex.im visualizes regular expressions:

enter image description here

Biome answered 7/11, 2019 at 23:16 Comment(0)
T
4

Javascript: /^(?=.*?\d)(?=.*?[a-z])[a-z\d]{18}$/i

These were the Salesforce Id validation requirements for me.

  1. 18 characters only
  2. At least one digit
  3. At least one alphabet
  4. Case insensitive

Test cases

Should fail

1
a
1234
abgcde
1234aDcde
12345678901234567*
123456789012345678
abcDefghijabcdefgh

Should pass

1234567890abcDeFgh
1234abcd1234abcd12
abcd1234abcd1234ab
1abcDefhijabcdefgf
abcDefghijabcdefg1
12345678901234567a
a12345678901234567

For understanding the regex, please refer this thread

Thirzi answered 27/8, 2020 at 13:8 Comment(0)
M
2

The regex provided by Daniel Sokolowski works perfectly to verify if the id is in the correct format.

If you want to verify if an id corresponds to an actual record in the database, you'll need to first find the object type from the first three characters (commonly known as prefix) and then query the object type:

boolean isValidAndExists(String key) {
    Map<String, Schema.SObjectType> objTypes = Schema.getGlobalDescribe();

    for (Schema.SObjectType objType : objTypes.values()) {
        Schema.DescribeSObjectResult objDesc = objType.getDescribe();
        if (objDesc.getKeyPrefix() == key.substring(0,3)) {
            String objName = objDesc.getName();
            String query = 'SELECT Id FROM ' + objName + ' WHERE Id = \'' + key + '\'';
            SObject[] objs = Database.query(query);
            return !objs.isEmpty();
        }
    }
    return false;
}

Be aware that Schema.getGlobalDescribe can be an expensive operation and degrade the performance of your application if you use that often. If you need to check that often, I recommend creating a Custom Setting or Custom Metadata to store the relation between prefixes and object types.

Motor answered 7/11, 2019 at 22:20 Comment(0)
D
1

Assuming you want to validate Ids in Apex, there are a few approaches discussed in the other answers. Here is an alternative, with notes on the various approaches.

The try-catch method (credit to @matt_k) certainly works, but some folks worry about overhead, especially if testing many Ids.

I used instanceof Id for a long time (credit to @melani_s), until I discovered that it sometimes gives the wrong answer (e.g., '481D0B74-41CF-47E9').

Multiple answers suggest regexen. As the accepted answer correctly points out (credit to @zacheusz), 18 character Ids are only valid if their checksums are correct, which means the regex solutions can be wrong. That answer also helpfully provides code in several languages to test Id checksums. But not in Apex.

I was going to implement the checksum code in Apex, but then I realized the Salesforce had already done the work, so instead I just convert 18 digit Ids to 15 digit Ids (via .to15() which uses the checksum to fix capitalization, as opposed to truncating the string) and then back to 18 digits to let SF do the checksum calc, then I compare the original checksum and the new one. This is my method:

    static Pattern ID_REGEX = Pattern.compile('[a-zA-Z0-9]{15}(?:[A-Z0-5]{3})?');
    /**
     * @description Determines if a string is a valid SalesforceId.  Confirms checksum of 18 digit Ids. 
     *              Works for cases where `x instanceof id` returns the wrong answer, like '481D0B74-41CF-47E9'.
     *              Does NOT check for the existence of a record with the given Id.
     * @param s     a string to validate 
     *
     * @return      true if the string `s` is a valid Salesforce Id.
     */
    public static Boolean isValidId(String s) {
        Matcher m = ID_REGEX.matcher(s);
        if (m.matches() == false) return false;     // if it doesn't match the regex it cannot be valid
        if (s.length() == 15) return true;          // if 15 char string matches the regex, assume it must be valid
        String check = (Id)((Id)s).to15();          // Convert to 15 char Id, then to Id and back to string, giving correct 18-char Id
        return s.right(3) == check.right(3);        // if 18 char string matches the regex, valid if checksum correct
    }
Dietsche answered 8/7, 2022 at 15:6 Comment(0)
B
1

Additionally checking getSObjectType() != null would be perfect if we are dealing with Salesforce records

public static boolean isRecordId(string recordId){
    try {
        return string.isNotBlank(recordId) && ((Id)recordId.trim()).getSObjectType() != null;
    } catch(Exception ex) {
        return false;
    }
}
Beaulahbeaulieu answered 9/1, 2023 at 16:9 Comment(0)
S
1

The first 15 characters of the Salesforce Id use base-62 encoding, which consists of the lower and upper case letters a-z, A-Z and the numbers 0–9.

The last 3 characters are optional and actually can only be upper case letters A-Z and numbers between 0-5, for a set of 32 lookup table characters.

So here's the regular expression that translates this:

[a-zA-Z0-9]{15}([A-Z0-5]{3})?

If you care about the optional last 3 characters being in a non-capturing group:

[a-zA-Z0-9]{15}(?:[A-Z0-5]{3})?
Spermogonium answered 21/6, 2023 at 15:39 Comment(0)
G
0
import re

def is_valid_salesforce_id(sfid):
    # Salesforce ID format: 15 or 18 characters, alphanumeric
    pattern = re.compile(r'^[a-zA-Z0-9]{15}(?:[a-zA-Z0-9]{3})?$')
    return bool(pattern.match(sfid))

# Example Usage
sfid_to_check = '0012x000004H3v1AAC'
if is_valid_salesforce_id(sfid_to_check):
    print(f"{sfid_to_check} is a valid Salesforce ID.")
else:
    print(f"{sfid_to_check} is not a valid Salesforce ID.")
Geode answered 4/3 at 18:24 Comment(1)
This answer, as written, provides little context for the code provided. Please add additional information to make it clearer how this answers the question.Aiglet

© 2022 - 2024 — McMap. All rights reserved.