Convierta el ID de 15 caracteres de Salesforce a 18 caracteres

20

En Salesforce CRM , cada objeto tiene una ID alfanumérica de 15 caracteres, que distingue entre mayúsculas y minúsculas. Si alguien tiene curiosidad, en realidad es el número base 62 . Sin embargo, las herramientas utilizadas para la migración e integración de datos pueden o no admitir mayúsculas y minúsculas. Para superar eso, las ID se pueden convertir de manera segura en ID alfanuméricas que no distinguen entre mayúsculas y minúsculas de 18 caracteres. En ese proceso, se agrega suma de verificación alfanumérica de 3 caracteres a la ID. El algoritmo de conversión es:

Ejemplo :

a0RE000000IJmcN
  1. Divide la identificación en tres fragmentos de 5 caracteres.

    a0RE0  00000  IJmcN
    
  2. Invierta cada trozo.

    0ER0a  00000  NcmJI
    
  3. Reemplace cada personaje en cada fragmento por 1si está en mayúscula o por 0lo contrario.

    01100  00000  10011
    
  4. Para cada número binario de 5 dígitos i, obtenga el carácter en la posición ien concatenación del alfabeto en mayúscula y los dígitos 0-5 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ012345).

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

    Flexible:

    M  A  T
    
  5. Agregue estos caracteres, la suma de verificación, a la ID original.

Salida :

a0RE000000IJmcNMAT

Escriba un programa o función que tome una cadena alfanumérica de 15 caracteres (ASCII) como entrada y devuelva una ID de 18 caracteres.

La validación de entrada está fuera del alcance de esta pregunta. Los programas pueden devolver cualquier valor o bloquearse en una entrada no válida.

Por favor, no use las características de los lenguajes propios de Salesforce que hacen que este desafío sea trivial (como la fórmula CASESAFEID(), la conversión Ida StringAPEX & c).

Casos de prueba

a01M00000062mPg    -> a01M00000062mPgIAI
001M000000qfPyS    -> 001M000000qfPySIAU
a0FE000000D6r3F    -> a0FE000000D6r3FMAR
0F9E000000092w2    -> 0F9E000000092w2KAA
aaaaaaaaaaaaaaa    -> aaaaaaaaaaaaaaaAAA
AbCdEfGhIjKlMnO    -> AbCdEfGhIjKlMnOVKV
aBcDEfgHIJKLMNO    -> aBcDEfgHIJKLMNO025
Trang Oul
fuente
3
Lamentablemente, la conversión de una cadena a un Id en Apex Code aún no sería más corta que algunas de las respuestas proporcionadas aquí, especialmente si el código debe ser autónomo. Apex Code no es adecuado para jugar al golf.
phyrfox el
2
@phyrfox como ex desarrollador de salesforce. Apex no es adecuado para mucho ...
Mike McMahon
2
APEX, 56 Bytes: public class X{public X(Id i){System.debug((String)i);}}. Sin embargo, solo funciona con ID de Salesforce válidas.
Trang Oul
Vine aquí buscando hacer esto por trabajo ( success.jitterbit.com/display/DOC/… ) , no golf, pero estoy un poco confundido por la descripción del algoritmo. Usted dice que cada fragmento invertido y desinfectado en el paso 4 será un "número binario", pero nunca reemplaza los dígitos 2-8 por 0 y 1. ¿Qué se supone que debo hacer exactamente para el paso 4 cuando los pasos 1-3 en un fragmento como "62mPg" han dado como resultado un número como "01026"?
k ..

Respuestas:

6

Ruby, 97 bytes

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

Este tiene algunos trucos muy buenos.

Mi instinto original para dividir la cadena en grupos de 5 caracteres fue 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]]

Resulta que eso es muuuuucho tiempo en comparación con una simple expresión regular ( x.chars.each_slice(5)vs. x.scan(/.{5}/)). Esto parece obvio en retrospectiva, pero nunca lo pensé realmente ... tal vez pueda optimizar algunas de mis viejas respuestas de Ruby aquí.

Sin embargo, lo que más me enorgullece en esta respuesta es este código:

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

Muy bien, así que aquí hay algunos antecedentes para los no rubíes. Ruby separa completamente los booleanos ( TrueClass, FalseClass) de los enteros / números ( Numeric), lo que significa que tampoco hay conversión automática de verdadero a 1 y falso a 0. Esto es molesto durante el golf (pero algo bueno ... para todos los demás fines).

El enfoque ingenuo para verificar si un solo carácter es mayúscula (y devolver 1 o 0) es

y.upcase==y?1:0

Podemos bajar esto un poco más (de nuevo, con una expresión regular):

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

Pero entonces realmente empecé a pensar. Hmm ... =~devuelve el índice de una coincidencia (por lo tanto, para nuestro único personaje, siempre 0si hay una coincidencia) o, nilen caso de no coincidir, un valor falso (todo lo demás excepto FalseClasses verdad en Ruby). El ||operador toma su primer operando si es verdadero, y su segundo operando de lo contrario. Por lo tanto, podemos jugar golf hasta

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

Muy bien, veamos qué está pasando aquí. Si yes una letra mayúscula, no coincidirá [^A-Z], por lo que la parte regex volverá nil. nil || 1es decir 1, las letras mayúsculas se vuelven 1. Si yes cualquier cosa menos una letra mayúscula, la parte regex regresará 0(porque hay una coincidencia en el índice 0), y como 0es verdad, lo 0 || 1es 0.

... y solo después de escribir todo esto me doy cuenta de que en realidad tiene la misma longitud que y=~/[A-Z]/?1:0. Jaja, oh bueno.

Pomo de la puerta
fuente
6

Pyth, 23 22 bytes

1 byte guardado por FryAmTheEggman .

sm@s+JrG1U6i}RJ_d2c3pz

Pruébalo en línea. Banco de pruebas.

Esta podría ser la primera vez que utilizo la pinstrucción rint en golf.

Explicación

     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
PurkkaKoodari
fuente
4

MATL , 24 bytes

j1Y24Y2hG5IePtk=~!XB1+)h

Utiliza la versión actual (9.1.0) del lenguaje / compilador.

Ejemplos

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

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

Explicación

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
Luis Mendo
fuente
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

Prueba

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>

edc65
fuente
2

CJam, 27 bytes

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

Ejecute todos los casos de prueba.

Una implementación bastante sencilla de la especificación. La parte más interesante es la conversión a caracteres en la suma de verificación. Agregamos 17 al resultado de cada fragmento. Tome ese módulo 43 y agregue el resultado de eso al personaje '0.

Martin Ender
fuente
2

Japt, 46 bytes

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

No estoy muy contento con la longitud, pero no puedo encontrar una manera de jugar golf. Pruébalo en línea!

ETHproducciones
fuente
2

JavaScript (ES6), 137 132 bytes

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

¡4 bytes guardados gracias a @ ՊՓԼՃՐՊՃՈԲՍԼ !

Explicación

Este desafío no es adecuado para JavaScript en absoluto. No hay una forma corta de revertir una cadena y parece que la forma más corta de convertir el número en un carácter es codificar cada carácter posible.

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 se permitiera que los dígitos en la suma de verificación fueran minúsculas, se podría hacer en 124 bytes de esta manera:

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

Prueba

usuario81655
fuente
Si no me equivoco, parseInt([...n].reverse().join``,2)podría cambiarse a +`0b${[...n].reverse().join``}`.
Mama Fun Roll
@ ՊՓԼՃՐՊՃՈԲՍԼ ¡Tienes razón! También guardé otro byte además de eso, gracias.
user81655
Ahorre 10 bytes completos mediante el uso .replace(/.{5}/g,n=>/*stuff*/).
Neil
2

MATLAB, 100 98 bytes

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

Se solicitará una cadena como entrada y la salida se mostrará en la pantalla.

Explicación

Probablemente estoy usando el enfoque más directo aquí:

  • Solicitud de entrada
  • Reformar a 5 (filas) x 3 (columnas)
  • Voltear el orden de la fila
  • Transponga la matriz para prepararla para ser leída como binaria
  • Asignar la matriz ABC ... XYZ012345
  • Compare los índices de caracteres de la matriz transpuesta con su equivalente en minúsculas y convierta los booleanos en cadenas, que luego se leen como binarios y se convierten a decimales.
  • Interprete estos decimales (incrementados en 1) como índices de la matriz asignada.
  • Mostrar la entrada con los 3 caracteres adicionales

¡Ahora por debajo de 100 bytes gracias a Luis Mendo!

slvrbld
fuente
1
Puedes ahorrar un poco usandoe=['A':'Z',48:53]
Luis Mendo
Veo que mi enfoque es casi el mismo que el tuyo :-)
Luis Mendo
2

PHP, 186181 bytes

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

Sin pelar

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

Empecé pensando que podría hacerlo mucho más corto que esto, pero se me acabaron las ideas para hacerlo más corto.

Samsquanch
fuente
1

Python 2, 97 bytes

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])
TFeld
fuente
1

PowerShell, 162 bytes

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, muchas cosas interesantes están sucediendo en este caso. Comenzaré con la segunda línea.

Tomamos la entrada como una cadena a través $args[0]y la configuramos $apara su uso posterior. Esto se encapsula ()para que se ejecute y se devuelva el resultado (es decir, $a) para que podamos concatenarlo inmediatamente con los resultados de tres llamadas a funciones (f ...). Cada llamada de función pasa como argumento la cadena de entrada indexada en fragmentos de orden inverso como una matriz de caracteres, lo que significa, para la entrada de ejemplo, $a[4..0]será igual@('0','E','R','0','a') a cada entrada como un carácter, no una cadena.

Ahora a la función, donde está la verdadera carne del programa. Tomamos la entrada como $f, pero solo se usa hacia el final, así que centrémonos allí, primero. Dado que se pasa como una matriz de caracteres (gracias a nuestra indexación anterior), podemos canalizarlo inmediatamente en un bucle con $f|%{...}. Dentro del bucle, tomamos cada carácter y realizamos una coincidencia de expresiones regulares entre mayúsculas y minúsculas con la -cmatchcual dará como resultado verdadero / falso si es mayúscula / de lo contrario. Lo convertimos como un entero con la encapsulación +(), luego esa matriz de 1 y 0 se -joinedita para formar una cadena. Eso luego se pasa como el primer parámetro en la [convert]::ToInt32()llamada .NET para cambiar el binario (base2 ) en decimal. Usamos ese número decimal resultante para indexar en una cadena (-join(...)[...]) La cadena se formula primero como un rango (65..90)que se convierte como una matriz de caracteres, luego se concatena con el rango(0..5)(es decir, la cadena es "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"). Todo eso es devolver el carácter apropiado de la cadena.

AdmBorkBork
fuente
1

Jolf, 30 bytes

Por último, ¡probablemente todavía sea un jolfable! Pruébalo aquí!

+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"
Conor O'Brien
fuente
1

Python 3, 201174138 bytes

Muchas gracias a Trang Oul por señalar una declaración de función que ya no necesitaba existir. Y operadores ternarios de Python. Y alguna salida incorrecta. Solo ... solo dale los votos positivos.

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)
Steve Eckert
fuente
Utiliza la función z()una vez, puede reemplazar su llamada y guardar 25 bytes. Además, su código se asigna incorrectamente en [lugar de 0.
Trang Oul
Bueno, fue un descuido vergonzoso de mi parte. Gracias.
Steve Eckert
1
Puede ahorrar aún más reemplazando primero if elsecon esta construcción y el segundo con operador ternario.
Trang Oul
1

J, 36 bytes

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

Uso:

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

Pruébelo en línea aquí.

randomra
fuente
1

C, 120 118 bytes

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

Funciona para cualquier entrada cuya longitud sea múltiplo de 5 :)

Sin 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);
    }
}
Cole Cameron
fuente
Para guardar algunos bytes, puede eliminar n del espacio de nombres global si usa main (n, v, s) para su firma, ya que de lo contrario no está usando argc.
cleblanc
También reemplace 26 * 17 con el viejo y normal 442 guarda otro byte
cleblanc
Con algunas ediciones más obtuve tu versión a 110 bytes. ¡No entiendo por qué tenías! Isupprer () cuando isupper () parece funcionar bien para mí. También refactoré tus bucles for para eliminar algunos innecesarios{} 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 Excelentes sugerencias, muchas gracias. El orden de las operaciones es muy importante en la n/26*17expresión, por lo que reemplazar con 442 no es una opción. Hasta!!isupper esa función no devuelve 1 para verdadero en mi sistema, devuelve 256. !!Es una forma corta de convertirlo a un valor de retorno 0/1 sin importar qué. YMMV.
Cole Cameron el
1

C #, 171 bytes

No estoy muy bien practicado en golf C #, pero aquí hay una oportunidad.

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;}
Cole Cameron
fuente
Sugerencias: char.IsUpper(t)se puede reemplazar cont>=65&t<=90 ( &en bool en C # es básicamente un campo de golf más &&corto sin cortocircuito). 447es más corto que 26*17. No es necesario que lo haga por separado Select: puede incluir el ternario directamente dentro del Sum. Considere reemplazar todos esos usos de Substringcon un bucle basado en su Takelugar, por ejemplo for(int i=0;i<3;i++)s.Skip(i*5).Take(5). Para referencia futura, u!=""sería más corto que u.Length>0(pero eso ya no es necesario si está usando Take).
Bob
La expresión n/26*17no es equivalente a n/442, pero aparte de eso, gracias por las sugerencias. Como se dijo, no tengo mucha experiencia en golf en C #, así que todo esto es algo excelente para mí para tener en cuenta en el futuro.
Cole Cameron
Ah, lo siento, leí mal.
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 lo solicita, revertiré mi código a legible y lo publicaré.

Yytsi
fuente
1

Python 3, 87 bytes

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))
Aleksi Torhamo
fuente