Converti un ID di 15 caratteri di Salesforce in 18 caratteri


20

In Salesforce CRM , ogni oggetto ha un ID alfanumerico di 15 caratteri, con distinzione tra maiuscole e minuscole. Se qualcuno è curioso, in realtà è il numero base-62 . Tuttavia, gli strumenti utilizzati per la migrazione e l'integrazione dei dati possono o meno supportare la distinzione tra maiuscole e minuscole. Per ovviare a ciò, gli ID possono essere tranquillamente convertiti in ID alfanumerici maiuscoli / minuscoli di 18 caratteri. In questo processo, il checksum alfanumerico di 3 caratteri viene aggiunto all'ID. L'algoritmo di conversione è:

Esempio :

a0RE000000IJmcN
  1. Dividi l'ID in tre blocchi di 5 caratteri.

    a0RE0  00000  IJmcN
    
  2. Invertire ogni blocco.

    0ER0a  00000  NcmJI
    
  3. Sostituisci ogni personaggio in ogni blocco con 1se maiuscolo o in 0caso contrario.

    01100  00000  10011
    
  4. Per ogni numero binario di 5 cifre i, ottenere il carattere nella posizione iin concatenazione dell'alfabeto maiuscolo e delle cifre 0-5 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ012345).

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

    cedendo:

    M  A  T
    
  5. Aggiungi questi caratteri, il checksum, all'ID originale.

Uscita :

a0RE000000IJmcNMAT

Scrivere un programma o una funzione che accetta come input una stringa alfanumerica (ASCII) di 15 caratteri e restituisce un ID di 18 caratteri.

La convalida dell'input non rientra nell'ambito di questa domanda. I programmi possono restituire qualsiasi valore o crash in caso di input non valido.

Per favore, non utilizzare le funzionalità di Salesforce lingue propretiary che rendono questa sfida banale (come la formula CASESAFEID(), la conversione Ida Stringin APEX & C).

Casi test

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

3
Purtroppo, la conversione di una stringa in un ID nel codice Apex non sarebbe comunque più breve di alcune delle risposte fornite qui, soprattutto se il codice deve essere autonomo. Il codice Apex non è adatto per il golf.
phyrfox, il

2
@phyrfox come ex sviluppatore di salesforce. L'apice non è adatto a molto ...
Mike McMahon,

2
APEX, 56 byte: public class X{public X(Id i){System.debug((String)i);}}. Funziona solo con ID Salesforce validi, tuttavia.
Trang Oul,

Sono venuto qui cercando di farlo davvero per lavoro ( success.jitterbit.com/display/DOC/… ) , non per il golf, ma sono un po 'confuso dalla descrizione dell'algoritmo. Dici che ogni blocco rovesciato e sterilizzato nel passaggio 4 sarà un "numero binario", ma non sostituirai mai le cifre 2-8 con 0 e 1. Cosa dovrei fare esattamente per il passaggio 4 quando i passaggi 1-3 su un blocco come "62mPg" hanno dato come risultato un numero come "01026"?
k ..

Risposte:


6

Rubino, 97 byte

->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

Questo ha alcuni trucchi davvero accurati.

Il mio istinto originale per dividere la stringa in gruppi di 5 caratteri era 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]]

Si scopre che è troppo lungo rispetto a una semplice regex ( x.chars.each_slice(5)vs. x.scan(/.{5}/)). Questo sembra ovvio col senno di poi, ma non ci ho mai pensato davvero ... forse posso ottimizzare alcune delle mie vecchie risposte di Ruby qui.

La cosa di cui sono più orgoglioso in questa risposta, però, è questo pezzo di codice:

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

Bene, quindi ecco alcuni retroscena dei non rubyisti. Ruby separa completamente i valori booleani ( TrueClass, FalseClass) da numeri interi / numeri ( Numeric), il che significa che non esiste alcuna conversione automatica da vero a 1 e falso in 0. Questo è fastidioso mentre si gioca a golf (ma è una buona cosa ... per tutti gli altri scopi).

L'approccio ingenuo per verificare se un singolo carattere è maiuscolo (e restituire 1 o 0) lo è

y.upcase==y?1:0

Possiamo abbassarlo un po 'di più (di nuovo, con una regex):

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

Ma poi ho iniziato davvero a pensare. Hmm ... =~restituisce l'indice di una partita (quindi, per il nostro singolo personaggio, sempre 0se c'è una corrispondenza) o nilin caso di mancata corrispondenza, un valore falso (tutto il resto tranne che FalseClassè vero in Ruby). L' ||operatore prende il suo primo operando se è vero, e il suo secondo operando in caso contrario. Pertanto, possiamo golf fino a

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

Bene, diamo un'occhiata a cosa sta succedendo qui. Se yè una lettera maiuscola, non riuscirà a corrispondere [^A-Z], quindi tornerà la parte regex nil. nil || 1è 1così diventano le lettere maiuscole 1. Se yè tutt'altro che una lettera maiuscola, la parte regex tornerà 0(perché c'è una corrispondenza all'indice 0), e poiché 0è vero, lo 0 || 1è 0.

... e solo dopo aver scritto tutto questo mi rendo conto che questa è in realtà la stessa lunghezza di y=~/[A-Z]/?1:0. Ahah, vabbè.


6

Pyth, 23 22 byte

1 byte salvato da FryAmTheEggman .

sm@s+JrG1U6i}RJ_d2c3pz

Provalo online. Suite di test.

Questa potrebbe essere la prima volta che utilizzo le pistruzioni Rint nel golf.

Spiegazione

     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 byte

j1Y24Y2hG5IePtk=~!XB1+)h

Utilizza la versione corrente (9.1.0) della lingua / compilatore.

Esempi

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

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

Spiegazione

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

Test

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 byte

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

Esegui tutti i casi di test.

Un'implementazione abbastanza semplice delle specifiche. La parte più interessante è la conversione in caratteri nel checksum. Aggiungiamo 17 al risultato di ogni blocco. Prendi quel modulo 43 e aggiungi il risultato al personaggio '0.


2

Japt, 46 byte

U+U®f"[A-Z]" ?1:0} f'.p5)®w n2 +A %36 s36 u} q

Non sono molto contento della lunghezza, ma non riesco a trovare un modo per giocare a golf. Provalo online!


2

JavaScript (ES6), 137 132 byte

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

4 byte salvati grazie a @ ՊՓԼՃՐՊՃՈԲՍԼ !

Spiegazione

Questa sfida non è adatta a JavaScript. Non esiste un modo breve per invertire una stringa e sembra che il modo più breve per convertire il numero in un carattere sia codificare ogni carattere possibile.

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``

Se alle cifre nel checksum fosse consentito di essere minuscole, ciò potrebbe avvenire in 124 byte in questo modo:

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``

Test


Se non sbaglio, parseInt([...n].reverse().join``,2)potrebbe essere cambiato in +`0b${[...n].reverse().join``}`.
Mama Fun Roll

@ ՊՓԼՃՐՊՃՈԲՍԼ Esatto! Ho anche salvato un altro byte, grazie.
user81655

Salvare 10 byte interi utilizzando .replace(/.{5}/g,n=>/*stuff*/).
Neil,

2

MATLAB, 100 98 byte

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

Una stringa verrà richiesta come input e l'output verrà visualizzato sullo schermo.

Spiegazione

Probabilmente sto usando l'approccio più diretto qui:

  • Richiedi input
  • Risagoma a 5 (righe) x 3 (colonne)
  • Capovolgi l'ordine delle righe
  • Trasponi la matrice per prepararla per essere letta come binaria
  • Allocare l'array ABC ... XYZ012345
  • Confronta gli indici dei caratteri della matrice trasposta con il suo equivalente minuscolo e converti i booleani in stringhe, che vengono quindi letti come binari e convertiti in decimali.
  • Interpreta questi decimali (incrementati di 1) come indici dell'array allocato.
  • Visualizza l'input con i 3 caratteri aggiuntivi

Ora sotto i 100 byte grazie a Luis Mendo!


1
Puoi risparmiare un po 'usandoe=['A':'Z',48:53]
Luis Mendo l'

Vedo che il mio approccio è quasi uguale al tuo :-)
Luis Mendo,

2

PHP, 186 181 byte

<?$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;

Ho iniziato pensando che avrei potuto renderlo molto più breve di così, ma ho finito le idee per renderlo più breve.


1

Python 2, 97 byte

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 byte

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, molte cose ordinate stanno accadendo in questo. Inizierò con la seconda riga.

Prendiamo l'input come stringa tramite $args[0]e lo impostiamo $aper l'uso in un secondo momento. Questo è incapsulato in ()modo da essere eseguito e il risultato restituito (cioè, $a) in modo che possiamo immediatamente concatenarlo con i risultati di tre chiamate di funzione (f ...). Ogni chiamata di funzione passa come argomento la stringa di input indicizzata in blocchi di ordine inverso come char-array - il che significa, per l'input di esempio, $a[4..0]sarà uguale @('0','E','R','0','a')a ciascuna voce come un carattere, non come una stringa.

Ora alla funzione, dove sta la vera carne del programma. Prendiamo input come $f, ma viene utilizzato solo verso la fine, quindi concentriamoci lì, prima. Dato che è passato come char-array (grazie alla nostra precedente indicizzazione), possiamo immediatamente collegarlo a un loop con $f|%{...}. All'interno del loop, prendiamo ogni personaggio ed eseguiamo una corrispondenza regex con distinzione tra maiuscole e minuscole con la -cmatchquale risulterà vero / falso se maiuscolo / altrimenti. Lo lanciamo come numero intero con l'incapsulamento +(), quindi quell'array di 1 e 0 viene -joineditato per formare una stringa. Questo viene quindi passato come primo parametro nella [convert]::ToInt32()chiamata .NET per modificare il binario (base 2) in decimale. Usiamo quel numero decimale risultante per indicizzare in una stringa (-join(...)[...]). La stringa viene prima formulata come un intervallo (65..90)che viene lanciato come un array di caratteri, quindi concatenato con l'intervallo (0..5)(ovvero, la stringa è "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"). Tutto ciò per restituire il carattere appropriato dalla stringa.


1

Jolf, 30 byte

Finalmente un probabilmente ancora giocoso! Provalo qui!

+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, 201 174 138 byte

Grazie mille a Trang Oul per aver sottolineato una dichiarazione di funzione che non doveva più esistere. E operatori ternari Python. E qualche output errato. Solo ... dagli solo i voti.

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)

Si utilizza la funzione z()una volta, è possibile sostituire la sua chiamata e salvare 25 byte. Inoltre, il codice viene assegnato in modo errato [anziché 0.
Trang Oul,

Bene, è stata una supervisione imbarazzante da parte mia. Grazie.
Steve Eckert,

1
Puoi risparmiare ancora di più sostituendo prima if elsecon questa costruzione e la seconda con l'operatore ternario.
Trang Oul,

1

J, 36 byte

,_5(u:@+22+43*<&26)@#.@|.\]~:tolower

Uso:

   (,_5(u:@+22+43*<&26)@#.@|.\]~:tolower) 'a0RE000000IJmcN'
a0RE000000IJmcNMAT

Provalo online qui.


1

C, 120 118 byte

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);}}

Funziona con qualsiasi input la cui lunghezza sia un multiplo di 5 :)

Ungolfed

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);
    }
}

Per salvare qualche byte puoi rimuovere n, dallo spazio dei nomi globale se usi main (n, v, s) per la tua firma poiché altrimenti non stai usando argc.
Cleblanc,

Sostituisci anche 26 * 17 con il vecchio 442 semplicemente salva un altro byte
cleblanc

Con qualche altra modifica ho portato la tua versione a 110 byte. Non capisco perché avevi !! isupprer () quando isupper () sembra funzionare bene per me. Inoltre ho rifatturato il tuo per i loop per rimuovere alcuni inutili{} 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 Suggerimenti eccellenti, grazie mille. L'ordine delle operazioni è molto importante n/26*17sull'espressione, quindi la sostituzione con 442 non è un'opzione. Per quanto riguarda !!isupper, quella funzione non restituisce 1 per vero sul mio sistema, restituisce 256. !!È un modo breve per convertirlo in un valore di ritorno 0/1, non importa quale. YMMV.
Cole Cameron,

1

C #, 171 byte

Non sono molto allenato nel golf C #, ma ecco un colpo.

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;}

Suggerimenti: char.IsUpper(t)può essere sostituito con t>=65&t<=90( &su bool in C # è sostanzialmente un golf- &&short senza corto circuito). 447è più corto di 26*17. Non è necessario fare un separato Select: è possibile includere il ternario direttamente all'interno di Sum. Prendi invece in considerazione la sostituzione di tutti quegli usi di Substringcon un loop basato su Take, ad es for(int i=0;i<3;i++)s.Skip(i*5).Take(5). Per riferimento futuro, u!=""sarebbe più breve di u.Length>0(ma non è più necessario se si utilizza Take).
Bob

L'espressione n/26*17non è equivalente n/442, ma a parte questo, grazie per i suggerimenti. Come detto, non ho molta esperienza nel golf in C #, quindi questa è una cosa grandiosa che dovrò considerare in futuro.
Cole Cameron,

Ah, scusa, l'ho letto male.
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;}

Se richiesto, ripristinerò il mio codice per renderlo leggibile e pubblicarlo.


1

Python 3, 87 byte

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.