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
Trang Oul
źródło
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óż.

Klamka
źródło
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
PurkkaKoodari
źródło
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
Luis Mendo
źródło
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>

edc65
źródło
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.

Martin Ender
źródło
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!

ETHprodukcje
źródło
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

użytkownik 81655
źródło
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!

slvrbld
źródło
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ć.

Samsquanch
źródło
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])
TFeld
źródło
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.

AdmBorkBork
źródło
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"
Conor O'Brien
źródło
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)
Steve Eckert
źródło
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

J, 36 bajtów

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

Stosowanie:

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

Wypróbuj online tutaj.

randomra
źródło
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);
    }
}
Cole Cameron
źródło
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;}
Cole Cameron
źródło
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ę.

Yytsi
źródło
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))
Aleksi Torhamo
źródło