Konwertuj 15-znakowy identyfikator Salesforce na 18-znakowy


20

W Salesforce CRM każdy obiekt ma 15-znakowy alfanumeryczny identyfikator, w którym rozróżniana jest wielkość liter. Jeśli ktoś jest ciekawy, w rzeczywistości jest to liczba podstawowa-62 . Jednak narzędzia używane do migracji i integracji danych mogą, ale nie muszą obsługiwać rozróżniania wielkości liter. Aby temu zaradzić, identyfikatory można bezpiecznie przekonwertować na alfanumeryczne identyfikatory bez rozróżniania wielkości liter. W tym procesie do ID dołączana jest 3-znakowa alfanumeryczna suma kontrolna. Algorytm konwersji to:

Przykład :

a0RE000000IJmcN
  1. Podziel identyfikator na trzy 5-znakowe części.

    a0RE0  00000  IJmcN
    
  2. Odwróć każdy fragment.

    0ER0a  00000  NcmJI
    
  3. Zastąp każdą postać w każdym fragmencie, 1jeśli ma wielkie litery lub 0jeśli inaczej.

    01100  00000  10011
    
  4. Dla każdej 5-cyfrowej liczby binarnej iuzyskaj znak w pozycji iw połączeniu wielkich liter i cyfr 0-5 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ012345).

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

    Wydajność:

    M  A  T
    
  5. Dołącz te znaki, sumę kontrolną, do oryginalnego identyfikatora.

Wyjście :

a0RE000000IJmcNMAT

Napisz program lub funkcję, która pobiera 15-znakowy ciąg alfanumeryczny (ASCII) jako dane wejściowe i zwraca 18-znakowy identyfikator.

Sprawdzanie poprawności danych wejściowych jest poza zakresem tego pytania. Programy mogą zwracać dowolną wartość lub ulegać awarii w przypadku nieprawidłowych danych wejściowych.

Proszę nie używać funkcji języków propretorialnych Salesforce, które sprawiają, że to wyzwanie jest trywialne (takie jak formuła CASESAFEID(), konwersja Iddo StringAPEX i c).

Przypadki testowe

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

3
Niestety, konwersja ciągu znaków na identyfikator w kodzie apeksowym nadal nie byłaby krótsza niż niektóre z podanych tutaj odpowiedzi, zwłaszcza jeśli kod musi być samodzielny. Kod Apex nie nadaje się do gry w golfa.
— phyrfox

2
@phyrfox jako były programista Salesforce. Apex nie nadaje się na wiele ...
— Mike McMahon

2
APEX, 56 bajtów: public class X{public X(Id i){System.debug((String)i);}}. Działa tylko z prawidłowymi identyfikatorami Salesforce.
— Trang Oul,

Przyszedłem tutaj, żeby zrobić to w pracy ( success.jitterbit.com/display/DOC/... ) , nie w golfa, ale trochę się mylę opisem algorytmu. Mówisz, że każdy odwrócony i odkażony fragment w kroku 4 będzie „liczbą binarną”, ale nigdy nie zastępujesz cyfr 2-8 cyframi 0 i 1. Co dokładnie powinienem zrobić dla kroku 4, gdy kroki 1-3 dla fragmentu takiego jak „62mPg” dały liczbę taką jak „01026”?
— k ..

Odpowiedzi:


6

Ruby, 97 bajtów

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

Ten ma naprawdę fajne sztuczki.

Mój pierwotny instynkt dzielenia łańcucha na grupy po 5 znaków to 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]]

Okazuje się, że jest to zbyt długie w porównaniu do zwykłego wyrażenia regularnego ( x.chars.each_slice(5)vs. x.scan(/.{5}/)). Z perspektywy czasu wydaje się to oczywiste, ale tak naprawdę nigdy o tym nie myślałem ... być może uda mi się zoptymalizować niektóre z moich starych odpowiedzi Ruby.

Najbardziej dumna z tej odpowiedzi jest jednak fragment kodu:

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

W porządku, oto kilka podstaw dla nie-Rubyistów. Ruby całkowicie oddziela wartości logiczne ( TrueClass, FalseClass) od liczb całkowitych / liczb ( Numeric) - co oznacza, że ​​nie ma automatycznej konwersji z prawdy na 1 i fałszu na 0. Jest to denerwujące podczas gry w golfa (ale dobra rzecz ... do wszystkich innych celów).

Naiwne podejście do sprawdzania, czy pojedynczy znak jest pisany wielkimi literami (i zwracanie 1 lub 0) to

y.upcase==y?1:0

Możemy to zrobić nieco dalej (ponownie, używając wyrażenia regularnego):

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

Ale potem naprawdę zacząłem myśleć. Hmm ... =~zwraca indeks dopasowania (więc dla naszego pojedynczego znaku, zawsze 0jeśli występuje dopasowanie) lub nilw przypadku braku dopasowania, wartość fałszowania (wszystko inne oprócz FalseClassprawdy w Ruby). ||Operator wykonuje swój pierwszy argument, jeśli to truthy, a jej drugi argument inaczej. Dlatego możemy zagrać w golfa do tego stopnia

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

Dobra, spójrzmy na to, co się tutaj dzieje. Jeśli yjest wielką literą, nie będzie pasować [^A-Z], więc część wyrażenia regularnego powróci nil. nil || 1jest 1, więc stają się wielkie litery 1. Jeśli yjest coś, ale wielką literą, regex część wróci 0(bo tam jest mecz w indeksie 0), a ponieważ 0jest truthy, 0 || 1jest 0.

... i dopiero po spisaniu tego wszystkiego zdaję sobie sprawę, że jest to faktycznie taka sama długość jak y=~/[A-Z]/?1:0. Haha, no cóż.


6

Pyth, 23 22 bajtów

1 bajt zapisany przez FryAmTheEggman .

sm@s+JrG1U6i}RJ_d2c3pz

Wypróbuj online. Zestaw testowy.

To może być pierwszy raz, kiedy użyłem pinstrukcji rint podczas gry w golfa.

Wyjaśnienie

     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 bajty

j1Y24Y2hG5IePtk=~!XB1+)h

Korzysta z bieżącej wersji (9.1.0) języka / kompilatora.

Przykłady

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

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

Wyjaśnienie

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 bajtów

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

Uruchom wszystkie przypadki testowe.

Dość prosta implementacja specyfikacji. Najbardziej interesującą częścią jest konwersja znaków na sumę kontrolną. Dodajemy 17 do wyniku każdej porcji. Weź ten modulo 43 i dodaj wynik tego do postaci '0.


2

Japt, 46 bajtów

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

Nie jestem zbyt zadowolony z długości, ale nie mogę znaleźć sposobu na grę w golfa. Wypróbuj online!


2

JavaScript (ES6), 137 132 bajtów

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

4 bajty zapisane dzięki @ ՊՓԼՃՐՊՃՈԲՍԼ !

Wyjaśnienie

To wyzwanie nie jest w ogóle odpowiednie dla JavaScript. Nie ma krótkiego sposobu na odwrócenie łańcucha i wygląda na to, że najkrótszym sposobem na konwersję liczby na znak jest zakodowanie na stałe każdego możliwego znaku.

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

Gdyby cyfry w sumie kontrolnej były małe, można by to zrobić w 124 bajtach w następujący sposób:

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


Jeśli się nie mylę, parseInt([...n].reverse().join``,2)można zmienić na +`0b${[...n].reverse().join``}`.
— Mama Fun Roll

@ ՊՓԼՃՐՊՃՈԲՍԼ Masz rację! Poza tym dzięki temu zaoszczędziłem jeszcze jeden bajt.
— user81655,

Zaoszczędź 10 całych bajtów .replace(/.{5}/g,n=>/*stuff*/).
— Neil

2

MATLAB, 100 98 bajtów

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

Jako dane wejściowe zostanie zażądany ciąg, a dane wyjściowe zostaną wyświetlone na ekranie.

Wyjaśnienie

Prawdopodobnie używam tutaj najbardziej bezpośredniego podejścia:

  • Poproś o wejście
  • Przekształć w 5 (wiersze) x 3 (kolumny)
  • Odwróć kolejność wierszy
  • Transponuj macierz, aby przygotować ją do odczytu jako plik binarny
  • Przydziel tablicę ABC ... XYZ012345
  • Porównaj wskaźniki znakowe transponowanej macierzy z jej małymi literami i przekonwertuj wartości logiczne na ciągi, które są następnie odczytywane jako binarne i przekształcane na dziesiętne.
  • Interpretuj te miejsca dziesiętne (zwiększane o 1) jako wskaźniki przydzielonej tablicy.
  • Wyświetl dane wejściowe za pomocą dodatkowych 3 znaków

Teraz poniżej 100 bajtów dzięki Luisowi Mendo!


1
Możesz trochę zaoszczędzić, używające=['A':'Z',48:53]
— Luis Mendo

Widzę, że moje podejście jest prawie takie samo jak twoje :-)
— Luis Mendo

2

PHP, 186 181 bajtów

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

Nieklofowany

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

Zacząłem myśleć, że mogę to zrobić o wiele krócej, ale zabrakło mi pomysłów, aby go skrócić.


1

Python 2, 97 bajtów

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 bajty

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, wiele fajnych rzeczy dzieje się w tym. Zacznę od drugiej linii.

Pobieramy dane wejściowe jako ciąg znaków $args[0]i ustawiamy je $ana później. Jest on enkapsulowany, ()więc jest wykonywany, a wynik zwracany (tj. $a), Dzięki czemu możemy natychmiast połączyć łańcuch z wynikami trzech wywołań funkcji (f ...). Każde wywołanie funkcji przekazuje jako argument łańcuch wejściowy indeksowany w kawałkach w odwrotnej kolejności jako tablica znaków - co oznacza, że ​​na przykład dane wejściowe $a[4..0]będą równe @('0','E','R','0','a')każdemu wpisowi jako znak, a nie ciąg znaków.

Przejdźmy teraz do funkcji, w której znajduje się prawdziwe mięso programu. Przyjmujemy dane wejściowe jako $f, ale jest to używane tylko do końca, więc skupmy się na tym, najpierw. Ponieważ jest przekazywany jako tablica znaków (dzięki naszemu wcześniejszemu indeksowaniu), możemy natychmiast potokować go w pętli za pomocą $f|%{...}. Wewnątrz pętli bierzemy każdą postać i przeprowadzamy dopasowanie wyrażenia regularnego z rozróżnianiem wielkości liter, z -cmatchktórym wynikiem będzie prawda / fałsz, jeśli będzie to wielkie litery / inaczej. Rzucamy to jako liczbę całkowitą z enkapsulowaniem +(), a następnie tablica 1 i 0 jest -joinedytowana w celu utworzenia łańcucha. Jest on następnie przekazywany jako pierwszy parametr w [convert]::ToInt32()wywołaniu .NET w celu zmiany wartości binarnej (podstawowej 2) na dziesiętną. Używamy wynikowej liczby dziesiętnej do indeksowania w łańcuch (-join(...)[...]). Łańcuch jest najpierw formułowany jako zakres (65..90)rzutowany jako tablica znaków, a następnie łączony z zakresem (0..5)(tzn. Łańcuch jest "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"). Wszystko po to, aby zwrócić odpowiedni znak z łańcucha.


1

Jolf, 30 bajtów

Nareszcie, prawdopodobnie wciąż nie do przyjęcia! Wypróbuj tutaj!

+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 bajtów

Ogromne podziękowania dla Trang Oul za wskazanie deklaracji funkcji, która już nie musiała istnieć. I trójskładnikowe operatory Pythona. I niektóre nieprawidłowe dane wyjściowe. Po prostu ... po prostu daj mu głos.

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)

Używasz funkcji z()raz, możesz zastąpić jej wywołanie i zaoszczędzić 25 bajtów. Ponadto kod niepoprawnie przypisuje [zamiast 0.
— Trang Oul,

To był żenujący nadzór z mojej strony. Dzięki.
— Steve Eckert

1
Można zaoszczędzić nawet więcej, zastępując pierwszy if elsez tej konstrukcji , a drugi z potrójnego operatora.
— Trang Oul


1

DO, 120 118 bajtów

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

Działa dla każdego wejścia, którego długość jest wielokrotnością 5 :)

Nie golfił

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

Aby zaoszczędzić kilka bajtów, możesz usunąć n z globalnej przestrzeni nazw, jeśli używasz main (n, v, s) do podpisu, ponieważ inaczej nie używasz argc.
— cleblanc

Również zamień 26 * 17 na zwykły stary 442 zapisuje kolejny bajt
— cleblanc

Po kilku kolejnych edycjach Twoja wersja została zmniejszona do 110 bajtów. Nie rozumiem, dlaczego miałeś !! isupprer (), kiedy wydaje się, że isupper () działa dobrze dla mnie. {} 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]));}
— Przebudowałem

@cleblanc Doskonałe sugestie, wielkie dzięki. Kolejność operacji jest bardzo ważna dla n/26*17wyrażenia, więc zamiana na 442 nie jest opcją. O ile !!isupperfunkcja ta nie zwraca 1 dla wartości true w moim systemie, zwraca 256. !!Jest to krótki sposób na przekonwertowanie jej na wartość zwracaną 0/1 bez względu na wszystko. YMMV.
— Cole Cameron,

1

C #, 171 bajtów

Nie jestem zbyt dobrze wyszkolony w golfie w C #, ale tutaj jest szansa.

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

Sugestie: char.IsUpper(t)można go zastąpić t>=65&t<=90( &on bool w C # jest w zasadzie krótszym golfem &&bez zwarcia). 447jest krótszy niż 26*17. Nie musisz robić osobnego Select: możesz dołączyć trójkę bezpośrednio do Sum. Zastanów się nad zastąpieniem tych wszystkich zastosowań Substringpętlą opartą na Takenp for(int i=0;i<3;i++)s.Skip(i*5).Take(5). W przyszłości u!=""będzie krótszy niż u.Length>0(ale nie jest to już konieczne, jeśli używasz Take).
— Bob

Wyrażenie n/26*17nie jest równoważne n/442, ale poza tym, dzięki za sugestie. Jak już wspomniano, nie mam zbyt dużego doświadczenia w grze w golfa w C #, więc to wszystko jest dla mnie świetne do rozważenia w przyszłości.
— Cole Cameron,

Ach, przepraszam - źle to odczytałem.
— 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;}

Na żądanie cofnę kod z powrotem do czytelnego i opublikuję.


1

Python 3, 87 bajtów

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))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.