Converter o ID do Salesforce de 15 caracteres em 18 caracteres


20

No Salesforce CRM , todo objeto tem um ID alfanumérico de 15 caracteres, que diferencia maiúsculas de minúsculas. Se alguém está curioso, na verdade é o número da base 62 . No entanto, as ferramentas usadas para migração e integração de dados podem ou não suportar a distinção entre maiúsculas e minúsculas. Para superar isso, os IDs podem ser convertidos com segurança em IDs alfanuméricos que não diferenciam maiúsculas de minúsculas de 18 caracteres. Nesse processo, a soma de verificação alfanumérica de 3 caracteres é anexada ao ID. O algoritmo de conversão é:

Exemplo :

a0RE000000IJmcN
  1. Divida o ID em três blocos de 5 caracteres.

    a0RE0  00000  IJmcN
    
  2. Inverta cada pedaço.

    0ER0a  00000  NcmJI
    
  3. Substitua cada caractere em cada pedaço por 1se estiver em maiúsculas ou por 0outro modo.

    01100  00000  10011
    
  4. Para cada número binário de 5 dígitos i, obtenha o caractere na posição iem concatenação do alfabeto maiúsculo e os dígitos 0-5 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ012345).

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

    Produzindo:

    M  A  T
    
  5. Anexe esses caracteres, a soma de verificação, ao ID original.

Saída :

a0RE000000IJmcNMAT

Escreva o programa ou a função que usa a sequência alfanumérica de 15 caracteres (ASCII) como entrada e retorna a identificação de 18 caracteres.

A validação de entrada está fora do escopo desta questão. Os programas podem retornar qualquer valor ou falha na entrada inválida.

Por favor, não use os recursos de idiomas apropriados do Salesforce que tornam esse desafio trivial (como fórmula CASESAFEID(), conversão Idpara StringAPEX etc.).

Casos de teste

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

3
Infelizmente, a conversão de uma sequência de caracteres em um ID no código Apex ainda não seria mais curta do que algumas das respostas fornecidas aqui, especialmente se o código precisar ser independente. O Código Apex não é adequado para jogar golfe.
Phyrfox

2
@phyrfox como um ex-desenvolvedor da força de vendas. Apex não é adequado para tanto ...
Mike McMahon

2
APEX, 56 bytes: public class X{public X(Id i){System.debug((String)i);}}. Porém, funciona apenas com IDs válidos do Salesforce.
Trang Oul

Eu vim aqui procurando realmente fazer isso por trabalho ( success.jitterbit.com/display/DOC/… ) , não por golfe, mas estou um pouco confuso com a descrição do algoritmo. Você diz que cada pedaço invertido e higienizado na etapa 4 será um "número binário", mas nunca substitui os dígitos 2 a 8 pelos zeros e zeros. O que exatamente devo fazer na etapa 4 quando as etapas 1 a 3 de um pedaço como "62mPg" resultaram em um número como "01026"?
k ..

Respostas:


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 tem alguns truques realmente legais.

Meu instinto original de dividir a string em grupos de 5 caracteres foi 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]]

Acontece que está muito longo em comparação com um simples regex ( x.chars.each_slice(5)vs. x.scan(/.{5}/)). Isso parece óbvio em retrospectiva, mas eu realmente nunca pensei nisso ... talvez eu possa otimizar algumas das minhas respostas antigas de Ruby aqui.

O que mais me orgulha nesta resposta, porém, é este pedaço de código:

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

Tudo bem, então aqui estão alguns antecedentes para os não-rubiistas. O Ruby separa completamente os booleanos ( TrueClass, FalseClass) dos números inteiros / (Numeric ) - o que significa que não há conversão automática de verdadeiro para 1 e falso para 0 também. Isso é chato durante o golfe (mas uma coisa boa ... para todos os outros fins).

A abordagem ingênua de verificar se um único caractere está em maiúsculas (e retornar 1 ou 0) é

y.upcase==y?1:0

Podemos aprofundar isso um pouco mais (novamente, com uma expressão regular):

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

Mas então eu realmente comecei a pensar. Hmm ... =~retorna o índice de uma correspondência (portanto, para o nosso único personagem, sempre 0se houver uma correspondência) ou, nilna falta de correspondência, um valor falso (tudo o resto, excetoFalseClass em Ruby, é verdade). O ||operador pega seu primeiro operando, se for verdade, e seu segundo operando, caso contrário. Portanto, podemos jogar isso até

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

Tudo bem, vamos ver o que está acontecendo aqui. Se yfor uma letra maiúscula, ela não corresponderá [^A-Z], portanto a parte regex retornará nil. nil || 1é 1, então as letras maiúsculas se tornam 1. Se não yhouver uma letra maiúscula, a parte regex retornará 0(porque há uma correspondência no índice 0) e, como0 é verdade, 0 || 1é 0.

... e somente depois de escrever tudo isso eu percebo que esse é realmente o mesmo comprimento que y=~/[A-Z]/?1:0. Haha, tudo bem.


6

Pitão, 23 22 bytes

1 byte salvo por FryAmTheEggman .

sm@s+JrG1U6i}RJ_d2c3pz

Experimente online. Suíte de teste.

Esta pode ser a primeira vez que usei as pinstruções rint no golfe.

Explicação

     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 bytes

j1Y24Y2hG5IePtk=~!XB1+)h

Usa a versão atual (9.1.0) do idioma / compilador.

Exemplos

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

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

Explicação

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

Teste

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 bytes

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

Execute todos os casos de teste.

Uma implementação bastante direta das especificações. A parte mais interessante é a conversão em caracteres na soma de verificação. Adicionamos 17 ao resultado de cada bloco. Pegue esse módulo 43 e adicione o resultado disso ao personagem '0.


2

Japonês, 46 bytes

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

Não estou muito feliz com o comprimento, mas não consigo encontrar uma maneira de jogar golfe. Experimente online!


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 salvos graças a @ ՊՓԼՃՐՊՃՈԲՍԼ !

Explicação

Este desafio não é adequado para JavaScript. Não há uma maneira curta de reverter uma string e parece que a maneira mais curta de converter o número em um caractere é codificar cada caractere possível.

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 os dígitos na soma de verificação tiverem letras minúsculas, isso poderá ser feito em 124 bytes como este:

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

Teste


Se não me engano, parseInt([...n].reverse().join``,2)poderia ser alterado para +`0b${[...n].reverse().join``}`.
Mama Fun Roll

@ ՊՓԼՃՐՊՃՈԲՍԼ Você está certo! Também salvei outro byte, obrigado.
user81655

Salve 10 bytes inteiros usando .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)])

Uma sequência será solicitada como entrada e a saída será exibida na tela.

Explicação

Provavelmente estou usando a abordagem mais direta aqui:

  • Solicitar entrada
  • Remodelar para 5 (linhas) x 3 (colunas)
  • Virar a ordem das linhas
  • Transponha a matriz para prepará-la para ser lida como binária
  • Aloque a matriz ABC ... XYZ012345
  • Compare os índices de caracteres da matriz transposta ao seu equivalente em minúsculas e converta os booleanos em seqüências de caracteres, que são lidas como binárias e convertidas em decimal.
  • Interprete esses decimais (incrementados por 1) como índices da matriz alocada.
  • Exiba a entrada com os 3 caracteres adicionais

Agora abaixo de 100 bytes, graças a Luis Mendo!


1
Você pode economizar um pouco usandoe=['A':'Z',48:53]
Luis Mendo

Vejo a minha abordagem é quase o mesmo que o seu :-)
Luis Mendo

2

PHP, 186 181 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;

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;

Comecei pensando que poderia torná-lo muito mais curto do que isso, mas fiquei sem idéias para torná-lo mais curto.


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

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, muitas coisas legais acontecendo neste. Vou começar com a segunda linha.

Tomamos a entrada como uma string via $args[0]e configuramos $apara uso posterior. Isso é encapsulado ()para que seja executado e o resultado retornado (ou seja $a) , para que possamos concatená-lo imediatamente com os resultados de três chamadas de função (f ...). Cada chamada de função passa como argumento a string de entrada indexada em pedaços de ordem inversa como uma matriz de caracteres - o que significa, para a entrada de exemplo, $a[4..0]será igual a@('0','E','R','0','a') a cada entrada como um caractere, não uma string.

Agora, para a função, onde está a verdadeira carne do programa. Tomamos a entrada como $f, mas ela só é usada no final, então vamos nos concentrar primeiro. Como é passado como um array de caracteres (graças à nossa indexação anterior), podemos inseri-lo imediatamente em um loop com $f|%{...}. Dentro do loop, pegamos cada caractere e executamos uma correspondência de regex com distinção entre maiúsculas e minúsculas com a -cmatchqual resultará em true / false se estiver em maiúsculas / caso contrário. Nós convertemos isso como um número inteiro com o encapsulamento +(), então essa matriz de 1 e 0 é -joined para formar uma string. Isso é passado como o primeiro parâmetro na [convert]::ToInt32()chamada do .NET para alterar o binário (base2 ) em decimal. Usamos esse número decimal resultante para indexar em uma string (-join(...)[...]) A string é formulada primeiro como um intervalo (65..90)que é convertido como um array de caracteres, depois concatenado com o range (0..5)(ou seja, a string é "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"). Tudo isso é retornar o caractere apropriado da string.


1

Jolf, 30 bytes

Finalmente, um provavelmente ainda divertido! Experimente aqui!

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

Muito obrigado a Trang Oul por apontar uma declaração de função que não precisava mais existir. E operadores ternários do Python. E alguma saída incorreta. Apenas ... apenas dê a ele 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)

Você usa a função z()uma vez, pode substituir sua chamada e salvar 25 bytes. Além disso, seu código atribui incorretamente em [vez de 0.
Trang Oul

Bem, isso foi uma supervisão embaraçosa da minha parte. Obrigado.
Steve Eckert

1
Você pode economizar ainda mais, substituindo primeiro if elsepor essa construção e o segundo por operador ternário.
Trang Oul


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 qualquer entrada cujo comprimento seja múltiplo de 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);
    }
}

Para salvar alguns bytes, você pode remover n, do espaço para nome global, se usar main (n, v, s) para sua assinatura, pois você não está usando o argc.
cleblanc

Também substituir 26 * 17 com planície antiga 442 salva outro byte
cleblanc

Com mais algumas edições, reduzi sua versão para 110 bytes. Eu não entendo por que você teve !! isupprer () quando isupper () parece funcionar bem para mim. Também eu reformulado o seu loops para remover alguns desnecessários{} 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 sugestões, muito obrigado. A ordem das operações é muito importante na n/26*17expressão, portanto, substituir por 442 não é uma opção. Na medida em !!isupperque essa função não retorna 1 como verdadeira no meu sistema, ela retorna 256. !!É uma maneira curta de convertê-la em um valor de retorno 0/1, não importa o quê. YMMV.
Cole Cameron

1

C #, 171 bytes

Eu não sou muito bem praticado no golfe C #, mas aqui está uma chance.

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

Sugestões: char.IsUpper(t)pode ser substituído por t>=65&t<=90( &no bool em C # é basicamente um golf mais &&curto sem curto-circuito). 447é mais curto que 26*17. Você não precisa fazer um separado Select: você pode incluir o ternário diretamente no Sum. Considere substituir todos esses usos Substringpor um loop baseado em Takevez disso, por exemplo for(int i=0;i<3;i++)s.Skip(i*5).Take(5). Para referência futura, u!=""seria menor que u.Length>0(mas isso não é mais necessário se você estiver usando Take).
Bob

A expressão n/26*17não é equivalente a n/442, mas fora isso, obrigado pelas sugestões. Como afirmado, eu não sou muito experiente no golfe em C #, então isso é uma coisa excelente para eu considerar no futuro.
Cole Cameron

Ah, desculpe - eu interpretei isso errado.
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 solicitado, vou reverter meu código para legível e publicá-lo.


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))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.