Convertir l'ID Salesforce à 15 caractères en 18 caractères


20

Dans Salesforce CRM , chaque objet possède un ID alphanumérique à 15 caractères, qui respecte la casse. Si quelqu'un est curieux, c'est en fait le numéro de base 62 . Cependant, les outils utilisés pour la migration et l'intégration des données peuvent ou non prendre en charge la sensibilité à la casse. Pour surmonter cela, les identifiants peuvent être convertis en toute sécurité en identifiants alphanumériques insensibles à la casse de 18 caractères. Dans ce processus, une somme de contrôle alphanumérique à 3 caractères est ajoutée à l'ID. L'algorithme de conversion est:

Exemple :

a0RE000000IJmcN
  1. Divisez l'ID en trois morceaux de 5 caractères.

    a0RE0  00000  IJmcN
    
  2. Inversez chaque morceau.

    0ER0a  00000  NcmJI
    
  3. Remplacez chaque caractère de chaque bloc par 1s'il est en majuscule ou par 0sinon.

    01100  00000  10011
    
  4. Pour chaque nombre binaire à 5 chiffres i, obtenez le caractère à la position idans la concaténation de l'alphabet majuscule et des chiffres 0-5 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ012345).

    00000 -> A,
    00001 -> B,
    00010 -> C, ..., 
    11010 -> Z, 
    11011 -> 0, ...,
    11111 -> 5`
    

    Rendement:

    M  A  T
    
  5. Ajoutez ces caractères, la somme de contrôle, à l'ID d'origine.

Sortie :

a0RE000000IJmcNMAT

Écrire un programme ou une fonction qui prend en entrée une chaîne alphanumérique (ASCII) de 15 caractères et renvoie un ID de 18 caractères.

La validation des entrées est hors de portée de cette question. Les programmes peuvent retourner n'importe quelle valeur ou planter sur une entrée non valide.

S'il vous plaît, ne pas utiliser les fonctionnalités de Salesforce langues propretiary qui rendent ce défi trivial (comme la formule CASESAFEID(), la conversion Idà StringApex et c).

Cas de test

a01M00000062mPg    -> a01M00000062mPgIAI
001M000000qfPyS    -> 001M000000qfPySIAU
a0FE000000D6r3F    -> a0FE000000D6r3FMAR
0F9E000000092w2    -> 0F9E000000092w2KAA
aaaaaaaaaaaaaaa    -> aaaaaaaaaaaaaaaAAA
AbCdEfGhIjKlMnO    -> AbCdEfGhIjKlMnOVKV
aBcDEfgHIJKLMNO    -> aBcDEfgHIJKLMNO025

3
Malheureusement, la conversion d'une chaîne en un identifiant dans le code Apex ne serait toujours pas plus courte que certaines des réponses fournies ici, surtout si le code doit être autonome. Le code Apex n'est pas bien adapté au golf.
phyrfox

2
@phyrfox en tant qu'ancien développeur Salesforce. Apex ne convient pas pour beaucoup ...
Mike McMahon

2
APEX, 56 octets: public class X{public X(Id i){System.debug((String)i);}}. Fonctionne uniquement avec des ID Salesforce valides.
Trang Oul

Je suis venu ici pour réellement faire cela pour le travail ( success.jitterbit.com/display/DOC/… ) , pas pour le golf, mais je suis un peu confus par la description de l'algorithme. Vous dites que chaque bloc inversé et désinfecté à l'étape 4 sera un «nombre binaire», mais vous ne remplacez jamais les chiffres 2 à 8 par des 0 et des 1. Que dois-je faire exactement pour l'étape 4 lorsque les étapes 1 à 3 sur un morceau comme "62mPg" ont abouti à un nombre comme "01026"?
k ..

Réponses:


6

Rubis, 97 octets

->s{s+s.scan(/.{5}/).map{|x|[*?A..?Z,*?0..?5][x.reverse.gsub(/./){|y|y=~/[^A-Z]/||1}.to_i 2]}*''}
->s{               # define an anonymous lambda
s+                 # the original string plus...
s.scan(/.{5}/)     # get every group of 5 chars
.map{|x|           # map over each group of 5 chars...
[*?A..?Z,*?0..?5]  # build the array of A-Z0-5
[                  # index over it with...
x.reverse          # the 5-char group, reversed...
.gsub(/./){|y|     # ... with each character replaced with...
y=~/[^A-Z]/||1     # ... whether it's uppercase (0/1)...
}.to_i 2           # ... converted to binary
]                  # (end index)
}*''               # end map, join into a string
}                  # end lambda

Celui-ci a des trucs vraiment sympas.

Mon instinct d'origine pour diviser la chaîne en groupes de 5 caractères était each_slice:

irb(main):001:0> [*1..20].each_slice(5).to_a
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20]]

Il s'avère que c'est trop long par rapport à une simple expression régulière ( x.chars.each_slice(5)vs. x.scan(/.{5}/)). Cela semble évident avec le recul, mais je n'y ai jamais vraiment pensé ... peut-être que je peux optimiser certaines de mes anciennes réponses Ruby ici.

La chose dont je suis le plus fier dans cette réponse, cependant, est ce morceau de code:

y=~/[^A-Z]/||1

Très bien, voici donc quelques informations pour les non-rubis. Ruby sépare complètement les booléens ( TrueClass, FalseClass) des entiers / nombres (Numeric ) - ce qui signifie qu'il n'y a pas non plus de conversion automatique de vrai à 1 et faux à 0. C'est ennuyeux en jouant au golf (mais c'est une bonne chose ... à toutes autres fins).

L'approche naïve pour vérifier si un seul caractère est en majuscule (et renvoyer 1 ou 0) est

y.upcase==y?1:0

Nous pouvons descendre un peu plus loin (encore une fois, avec une expression régulière):

y=~/[A-Z]/?1:0

Mais j'ai vraiment commencé à réfléchir. Hmm ... =~retourne l'index d'une correspondance (donc, pour notre seul caractère, toujours 0s'il y a correspondance) ou nilen cas de non-correspondance, une valeur falsifiée (tout le reste sauf FalseClassest vrai en Ruby). L' ||opérateur prend son premier opérande s'il est vrai, et son deuxième opérande sinon. Par conséquent, nous pouvons jouer au golf jusqu'à

y=~/[^A-Z]/||1

D'accord, regardons ce qui se passe ici. Si yest une lettre majuscule, elle ne correspondra pas [^A-Z], donc la partie regex reviendra nil. nil || 1est 1, donc les lettres majuscules deviennent 1. Si yest autre chose qu'une lettre majuscule, la partie regex retournera 0(car il y a une correspondance à l'index 0), et comme 0c'est vrai, l' 0 || 1est 0.

... et seulement après avoir écrit tout cela, je me rends compte que c'est en fait la même longueur que y=~/[A-Z]/?1:0. Haha, eh bien.


6

Pyth, 23 22 octets

1 octet enregistré par FryAmTheEggman .

sm@s+JrG1U6i}RJ_d2c3pz

Essayez-le en ligne. Suite de tests.

C'est peut-être la première fois que j'utilise l' pinstruction de rint pour jouer au golf.

Explication

     JrG1                   save uppercase alphabet in J
                     z      input string
                    p       print it without newline
                  c3        split into 3 parts
 m              d           for each part:
               _              reverse
            }R                map characters to being in
              J                 uppercase alphabet (saved in J)
           i     2            parse list of bools as binary
  @                           get correct item of
     J                          uppercase alphabet (saved in J)
   s+    U6                     add nums 0-5 to it
s                           concatenate and print

4

MATL , 24 octets

j1Y24Y2hG5IePtk=~!XB1+)h

Utilise la version actuelle (9.1.0) du langage / compilateur.

Exemples

>> matl
 > j1Y24Y2hG5IePtk=~!XB1+)h
 >
> a0RE000000IJmcN
a0RE000000IJmcNMAT

>> matl
 > j1Y24Y2hG5IePtk=~!XB1+)h
 >
> a01M00000062mPg
a01M00000062mPgIAI

Explication

j            % input string
1Y2          % predefined literal: 'ABC...Z'
4Y2          % predefined literal; '012...9'
h            % concatenate into string 'ABC...Z012...9'
G            % push input string
5Ie          % reshape into 5x3 matrix, column-major order
P            % flip vertically
tk=~         % 1 if uppercase, 0 if lowercase
!XB1+        % convert each column to binary number and add 1
)            % index 'ABC...Z012...9' with resulting numbers
h            % concatenate result with original string

3

JavaScript (ES6), 108

x=>x.replace(/[A-Z]/g,(x,i)=>t|=1<<i,t=0)+[0,5,10].map(n=>x+='ABCDEFGHIJKLMNOPQRSTUVWXYZ012345'[t>>n&31])&&x

Tester

f=x=>x.replace(/[A-Z]/g,(x,i)=>t|=1<<i,t=0)+[0,5,10].map(n=>x+='ABCDEFGHIJKLMNOPQRSTUVWXYZ012345'[t>>n&31])&&x

// Less golfed

U=x=>{
  x.replace(/[A-Z]/g,(x,i)=>t|=1<<i,t=0); // build a 15 bit number (no need to explicit reverse)
  // convert 't' to 3 number of 5 bits each, then to the right char A..Z 0..5
  [0,5,10].forEach(n=> // 3 value for shifting
    x += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ012345' // to convert value to char
     [ t>>n&31 ] // shift and mask
  );
  return x
}

console.log=x=>O.innerHTML+=x+'\n';

;[
  ['a01M00000062mPg','a01M00000062mPgIAI']
, ['001M000000qfPyS','001M000000qfPySIAU']
, ['a0FE000000D6r3F','a0FE000000D6r3FMAR']
, ['0F9E000000092w2','0F9E000000092w2KAA']
, ['aaaaaaaaaaaaaaa','aaaaaaaaaaaaaaaAAA']
, ['AbCdEfGhIjKlMnO','AbCdEfGhIjKlMnOVKV']
, ['aBcDEfgHIJKLMNO','aBcDEfgHIJKLMNO025']
].forEach(t=>{
  var i=t[0],x=t[1],r=f(i);
  console.log(i+'->'+r+(r==x?' OK':' Fail (expected '+x+')'));
})
<pre id=O></pre>


2

CJam, 27 octets

l_5/{W%{_el=!}%2bH+43%'0+}%

Exécutez tous les cas de test.

Une implémentation assez simple de la spécification. La partie la plus intéressante est la conversion en caractères dans la somme de contrôle. Nous ajoutons 17 au résultat de chaque morceau. Prenez ce modulo 43 et ajoutez le résultat de cela au personnage '0.



2

JavaScript (ES6), 137 132 octets

s=>s+s.replace(/./g,c=>c>"9"&c<"a").match(/.{5}/g).map(n=>"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"[0|"0b"+[...n].reverse().join``]).join``

4 octets enregistrés grâce à @ ՊՓԼՃՐՊՃՈԲՍԼ !

Explication

Ce défi n'est pas du tout adapté à JavaScript. Il n'y a pas de moyen rapide d'inverser une chaîne et il semble que le moyen le plus court de convertir le nombre en caractère soit de coder en dur chaque caractère possible.

s=>
  s+                                   // prepend the original ID
  s.replace(/./g,c=>c>"9"&c<"a")       // convert each upper-case character to 1
  .match(/.{5}/g).map(n=>              // for each group of 5 digits
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
    [0|"0b"+                            // convert from binary
      [...n].reverse().join``]          // reverse the string
  ).join``

Si les chiffres de la somme de contrôle pouvaient être en minuscules, cela pourrait être fait en 124 octets comme ceci:

s=>s+s.replace(/./g,c=>c>"9"&c<"a").match(/.{5}/g).map(n=>((parseInt([...n].reverse().join``,2)+10)%36).toString(36)).join``

Tester


Si je ne me trompe pas, parseInt([...n].reverse().join``,2)pourrait être changé en +`0b${[...n].reverse().join``}`.
Mama Fun Roll

@ ՊՓԼՃՐՊՃՈԲՍԼ Vous avez raison! J'ai également enregistré un autre octet en plus, merci.
user81655

Économisez 10 octets entiers en utilisant .replace(/.{5}/g,n=>/*stuff*/).
Neil

2

MATLAB, 100 98 octets

s=input('');a=flip(reshape(s,5,3))';e=['A':'Z',48:53];disp([s,e(bin2dec(num2str(a~=lower(a)))+1)])

Une chaîne sera demandée en entrée et la sortie sera affichée à l'écran.

Explication

J'utilise probablement l'approche la plus simple ici:

  • Demander une entrée
  • Remodeler en 5 (lignes) x 3 (colonnes)
  • Inverser l'ordre des lignes
  • Transposer la matrice pour la préparer à la lecture en binaire
  • Allouer le tableau ABC ... XYZ012345
  • Comparez les indices de caractères de la matrice transposée à son équivalent en minuscules et convertissez les booléens en chaînes, qui sont ensuite lues en binaire et converties en décimales.
  • Interprétez ces décimales (incrémentées de 1) comme des indices du tableau alloué.
  • Afficher l'entrée avec les 3 caractères supplémentaires

Maintenant en dessous de 100 octets grâce à Luis Mendo!


1
Vous pouvez économiser un peu en utilisante=['A':'Z',48:53]
Luis Mendo

Je vois que mon approche est presque la même que la vôtre :-)
Luis Mendo

2

PHP, 186 181 octets

<?$z=$argv[1];$x=str_split($z,5);$l="ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";foreach($x as$y){foreach(str_split(strrev($y))as$a=>$w)$y[$a]=ctype_upper($w)?1:0;$z.=$l[bindec($y)];}echo $z;

Unglofed

<?php
$z = $argv[1];
$x = str_split($z,5);
$l = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
foreach($x as $y) {
    foreach( str_split( strrev($y) ) as $a => $w) {
        $y[$a] = ctype_upper($w) ? 1 : 0;
    }
    $z .= $l[bindec($y)];
}
echo $z;

J'ai commencé par penser que je pouvais le rendre beaucoup plus court que cela, mais j'ai manqué d'idées pour le raccourcir.


1

Python 2, 97 octets

lambda i:i+''.join(chr(48+(17+sum((2**j)*i[x+j].isupper()for j in range(5)))%43)for x in[0,5,10])

1

PowerShell, 162 octets

function f{param($f)-join([char[]](65..90)+(0..5))[[convert]::ToInt32(-join($f|%{+($_-cmatch'[A-Z]')}),2)]}
($a=$args[0])+(f $a[4..0])+(f $a[9..5])+(f $a[14..10])

OK, beaucoup de trucs sympas se passent dans celui-ci. Je vais commencer par la deuxième ligne.

Nous prenons l'entrée sous forme de chaîne via $args[0]et la configurons $apour une utilisation ultérieure. Ceci est encapsulé dans ()donc il est exécuté et le résultat est retourné (c'est-à-dire $a) afin que nous puissions immédiatement le concaténer en chaîne avec les résultats de trois appels de fonction (f ...). Chaque appel de fonction passe en argument la chaîne d'entrée indexée en morceaux dans l'ordre inverse comme un tableau de caractères - ce qui signifie, pour l'exemple d'entrée, $a[4..0]sera égal @('0','E','R','0','a')à chaque entrée en tant que caractère, pas une chaîne.

Passons maintenant à la fonction, où se trouve la vraie viande du programme. Nous prenons en compte$f , mais elles ne sont utilisées que vers la fin, alors concentrons-nous d'abord là-dessus. Puisqu'il est passé en tant que tableau de caractères (grâce à notre indexation précédente), nous pouvons immédiatement le diriger dans une boucle avec $f|%{...}. À l'intérieur de la boucle, nous prenons chaque caractère et effectuons une correspondance regex sensible à la casse avec -cmatchlaquelle se traduira par vrai / faux s'il est en majuscule / sinon. Nous convertissons cela en un entier avec l'encapsulation +(), puis ce tableau de 1 et de 0 est -joinédité pour former une chaîne. Cela est ensuite passé en tant que premier paramètre dans l' [convert]::ToInt32()appel .NET pour changer le binaire (base 2) en décimal. Nous utilisons ce nombre décimal résultant pour indexer dans une chaîne (-join(...)[...] ). La chaîne est d'abord formulée comme une plage (65..90)qui est convertie en un tableau de caractères,(0..5)(c'est-à-dire que la chaîne est "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"). Tout cela consiste à renvoyer le caractère approprié de la chaîne.


1

Jolf, 30 octets

Enfin, un probablement encore jolfable! Essayez-le ici!

+i mZci5d.p1CρA_Hpu1"[^1]'0"2
    Zci5                      split input into groups of 5
  _m                          map it
        d                      with this function
               _H              reverse H
              A  pu1            and replace in it all uppercase letters with 1
             ρ      "[^1]'0"    replace all non-ones with zeroes
            C               2   parse as binary integer
         .p1                    get the (^)th member of "A...Z0...9"

1

Python 3, 201174138 octets

Un grand merci à Trang Oul pour avoir souligné une déclaration de fonction qui n'avait plus besoin d'exister. Et les opérateurs ternaires Python. Et une sortie incorrecte. Donnez-lui juste les votes positifs.

i=input();n='';c=l=15;
while c:c-=1;n+=('0','1')[i[c].isupper()]
while l:v=int(n[l-5:l],2);l-=5;i+=(chr(v+65),str(v-26))[v>25]
print(i)

Vous utilisez la fonction z()une fois, vous pouvez remplacer son appel et économiser 25 octets. En outre, votre code attribue incorrectement [au lieu de 0.
Trang Oul

Eh bien, c'était une erreur embarrassante de ma part. Merci.
Steve Eckert

1
Vous pouvez économiser encore plus en remplaçant d'abord if elsepar cette construction et la seconde par un opérateur ternaire.
Trang Oul du


1

C, 120 118 octets

n,j;main(c,v,s)char**v,*s;{for(printf(s=v[1]);*s;s+=5){for(n=0,j=5;j--;)n=n*2+!!isupper(s[j]);putchar(n+65-n/26*17);}}

Fonctionne pour toute entrée dont la longueur est un multiple de 5 :)

Non golfé

n,j;

main(c,v,s) char **v, *s;
{
    for(printf(s = v[1]); *s; s+=5)
    {
        for(n=0, j=5; j--;)
            n=n*2+!!isupper(s[j]);

        putchar(n+65-n/26*17);
    }
}

Pour économiser quelques octets, vous pouvez supprimer n de l'espace de noms global si vous utilisez main (n, v, s) pour votre signature car vous n'utilisez pas autrement argc.
cleblanc

Remplacez également 26 * 17 par un simple vieux 442 enregistre un autre octet
cleblanc

Avec quelques modifications supplémentaires, j'ai réduit votre version à 110 octets. Je ne comprends pas pourquoi vous aviez !! isupprer () quand isupper () semble bien fonctionner pour moi. J'ai également refactorisé vos boucles pour supprimer certaines inutiles{} j;main(n,v,s)char**v,*s;{for(printf(s=v[1]);*s;s+=5,putchar(n+65-n/442))for(n=0,j=5;j--;n=n*2+isupper(s[j]));}
cleblanc

@cleblanc Excellentes suggestions, merci beaucoup. L'ordre des opérations est très important sur l' n/26*17expression, donc le remplacement par 442 n'est pas une option. Pour autant que!!isupper , cette fonction ne renvoie pas 1 pour vrai sur mon système, elle renvoie 256. Le !!est un moyen rapide de la convertir en valeur de retour 0/1, quoi qu'il arrive. YMMV.
Cole Cameron

1

C #, 171 octets

Je ne suis pas vraiment bien formé au golf C #, mais voici un coup.

s=>{for(var u=s;u.Length>0;u=u.Substring(5)){int p=0,n=u.Substring(0,5).Select(t=>char.IsUpper(t)?1:0).Sum(i=>(int)(i*Math.Pow(2,p++)));s+=(char)(n+65-n/26*17);}return s;}

Suggestions: char.IsUpper(t)peut être remplacé par t>=65&t<=90( &sur bool en C # est essentiellement un golf plus &&court sans court-circuit). 447est plus court que 26*17. Vous n'avez pas besoin de faire une séparation Select: vous pouvez inclure le ternaire directement dans le Sum. Envisagez de remplacer toutes ces utilisations de Substringpar une boucle basée sur Take, par exemple for(int i=0;i<3;i++)s.Skip(i*5).Take(5). Pour référence future, u!=""serait plus court que u.Length>0(mais ce n'est plus nécessaire si vous utilisez Take).
Bob

L'expression n/26*17n'est pas équivalente àn/442 , mais à part cela, merci pour les suggestions. Comme indiqué, je ne suis pas très expérimenté dans le golf en C # donc ce sont toutes des choses formidables pour moi à considérer à l'avenir.
Cole Cameron

Ah, désolé - je l'ai mal lu.
Bob

1

C # 334

string g(string c){string[]b=new string[]{c.Substring(0,5),c.Substring(5, 5),c.Substring(10)};string o="",w="";for(int i=0,j=0;i<3;i++){char[]t=b[i].ToCharArray();Array.Reverse(t);b[i]=new string(t);o="";for(j=0;j<5;j++){o+=Char.IsUpper(b[i][j])?1:0;}int R=Convert.ToInt32(o,2);char U=R>26?(char)(R+22):(char)(R+65);w+=U;}return c+w;}

Si demandé, je vais inverser mon code pour qu'il soit lisible et le publier.


1

Python 3, 87 octets

lambda s:s+bytes(48+(17+sum((~s[i+j]&32)>>(5-i)for i in range(5)))%43 for j in(0,5,10))
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.