Ubah ID 15 karakter Salesforce menjadi 18 karakter

20

Dalam Salesforce CRM , setiap objek memiliki ID alfanumerik 15 karakter, yang peka huruf besar-kecil. Kalau ada yang penasaran, sebenarnya itu nomor base-62 . Namun, alat yang digunakan untuk migrasi data dan integrasi mungkin atau mungkin tidak mendukung sensitivitas kasus. Untuk mengatasinya, ID dapat dikonversi dengan aman menjadi ID alfanumerik tidak sensitif huruf-18. Dalam proses itu checksum alfanumerik 3 karakter ditambahkan ke ID. Algoritma konversi adalah:

Contoh :

a0RE000000IJmcN
  1. Pisahkan ID menjadi tiga potongan 5 karakter.

    a0RE0  00000  IJmcN
    
  2. Membalikkan setiap potongan.

    0ER0a  00000  NcmJI
    
  3. Ganti setiap karakter di setiap chunk dengan 1huruf besar atau 0sebaliknya.

    01100  00000  10011
    
  4. Untuk setiap nomor biner 5 digit i, dapatkan karakter pada posisi idalam gabungan huruf besar dan angka 0-5 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ012345).

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

    Menghasilkan:

    M  A  T
    
  5. Tambahkan karakter-karakter ini, checksum, ke ID asli.

Keluaran :

a0RE000000IJmcNMAT

Tulis program atau fungsi yang menggunakan string 15-karakter alfanumerik (ASCII) sebagai input dan mengembalikan ID 18-karakter.

Validasi input di luar cakupan pertanyaan ini. Program dapat mengembalikan nilai atau kerusakan apa pun pada input yang tidak valid.

Tolong, jangan gunakan fitur bahasa propretiaris Salesforce yang membuat tantangan ini sepele (seperti formula CASESAFEID(), dikonversi Idke Stringdalam APEX & c).

Uji Kasus

a01M00000062mPg    -> a01M00000062mPgIAI
001M000000qfPyS    -> 001M000000qfPySIAU
a0FE000000D6r3F    -> a0FE000000D6r3FMAR
0F9E000000092w2    -> 0F9E000000092w2KAA
aaaaaaaaaaaaaaa    -> aaaaaaaaaaaaaaaAAA
AbCdEfGhIjKlMnO    -> AbCdEfGhIjKlMnOVKV
aBcDEfgHIJKLMNO    -> aBcDEfgHIJKLMNO025
Trang Oul
sumber
3
Sedihnya, mengonversi string menjadi Id dalam Kode Apex masih tidak akan lebih pendek dari beberapa jawaban yang diberikan di sini, terutama jika kode harus mandiri. Kode Apex tidak cocok untuk bermain golf.
phyrfox
2
@ phyrfox sebagai mantan tenaga penjualan. Puncak tidak cocok untuk banyak ...
Mike McMahon
2
APEX, 56 byte: public class X{public X(Id i){System.debug((String)i);}}. Hanya bekerja dengan ID Tenaga Penjualan yang valid.
Trang Oul
Saya datang ke sini mencari untuk benar-benar melakukan ini untuk bekerja ( success.jitterbit.com/display/DOC/… ) , bukan golf, tapi saya agak bingung dengan deskripsi algoritma. Anda mengatakan bahwa setiap potongan terbalik dan sanitasi pada langkah 4 akan menjadi "angka biner," tetapi Anda tidak pernah mengganti angka 2-8 dengan 0 dan 1. Apa sebenarnya yang harus saya lakukan untuk langkah 4 ketika langkah 1-3 pada chunk seperti "62mPg" telah menghasilkan angka seperti "01026"?
k ..

Jawaban:

6

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

Yang ini punya beberapa trik yang sangat rapi.

Insting asli saya untuk memisahkan string ke dalam kelompok 5 karakter adalah 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]]

Ternyata itu waaay terlalu lama dibandingkan dengan regex sederhana ( x.chars.each_slice(5)vs x.scan(/.{5}/)). Tampaknya ini jelas, tetapi saya tidak pernah benar-benar memikirkannya ... mungkin saya dapat mengoptimalkan beberapa jawaban Ruby saya yang lama di sini.

Namun, hal yang paling saya banggakan dalam jawaban ini adalah bagian kode ini:

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

Baiklah, jadi inilah beberapa latar belakang untuk yang bukan Ruby. Ruby benar-benar memisahkan booleans ( TrueClass, FalseClass) dari integer / angka ( Numeric) —yang berarti tidak ada konversi otomatis dari true ke 1 dan false ke 0 juga. Ini menjengkelkan saat bermain golf (tetapi hal yang baik ... untuk semua keperluan lainnya).

Pendekatan naif untuk memeriksa apakah satu karakter huruf besar (dan mengembalikan 1 atau 0) adalah

y.upcase==y?1:0

Kita bisa turun sedikit lebih jauh (sekali lagi, dengan regex):

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

Tetapi kemudian saya benar-benar mulai berpikir. Hmm ... =~mengembalikan indeks kecocokan (jadi, untuk karakter tunggal kami, selalu 0jika ada kecocokan) atau jika nilgagal mencocokkan, nilai palsu (semua yang lain kecuali FalseClassbenar di Ruby). The ||Operator mengambil operan pertama jika itu truthy, dan operan kedua sebaliknya. Oleh karena itu, kita dapat bermain golf ini hingga

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

Baiklah, mari kita lihat apa yang terjadi di sini. Jika yhuruf besar, itu akan gagal cocok [^A-Z], sehingga bagian regex akan kembali nil. nil || 1adalah 1, jadi huruf besar menjadi 1. Jika yapa pun selain huruf besar, bagian regex akan kembali 0(karena ada kecocokan pada indeks 0), dan karena 0itu benar, 0 || 1adalah 0.

... dan hanya setelah menulis semua ini saya menyadari bahwa ini sebenarnya sama panjangnya y=~/[A-Z]/?1:0. Haha, oh well.

Gagang pintu
sumber
6

Pyth, 23 22 byte

1 byte disimpan oleh FryAmTheEggman .

sm@s+JrG1U6i}RJ_d2c3pz

Cobalah online. Suite uji.

Ini mungkin pertama kalinya saya menggunakan pinstruksi rintisan dalam bermain golf.

Penjelasan

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

MATL , 24 byte

j1Y24Y2hG5IePtk=~!XB1+)h

Menggunakan versi saat ini (9.1.0) dari bahasa / kompiler.

Contohnya

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

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

Penjelasan

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

Uji

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

CJam, 27 byte

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

Jalankan semua test case.

Implementasi spec yang cukup mudah. Bagian yang paling menarik adalah konversi ke karakter dalam checksum. Kami menambahkan 17 ke hasil setiap potongan. Ambil modulo 43 itu dan tambahkan hasilnya ke karakter '0.

Martin Ender
sumber
2

Japt, 46 byte

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

Tidak terlalu senang dengan panjangnya, tetapi saya tidak dapat menemukan cara untuk menurunkannya. Cobalah online!

Produksi ETH
sumber
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 disimpan berkat @ ՊՓԼՃՐՊՃՈԲՍԼ !

Penjelasan

Tantangan ini tidak cocok untuk JavaScript sama sekali. Tidak ada cara pendek untuk membalikkan string dan sepertinya cara terpendek untuk mengubah angka menjadi karakter adalah dengan meng-hard-code setiap karakter yang mungkin.

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

Jika digit dalam checksum diizinkan menjadi huruf kecil, bisa dilakukan dalam 124 byte seperti ini:

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

Uji

pengguna81655
sumber
Jika saya tidak salah, parseInt([...n].reverse().join``,2)bisa diubah menjadi +`0b${[...n].reverse().join``}`.
Mama Fun Roll
@ ՊՓԼՃՐՊՃՈԲՍԼ Benar kamu! Saya menyimpan byte lain di atas itu juga, terima kasih.
user81655
Simpan 10 byte penuh dengan menggunakan .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)])

Sebuah string akan diminta sebagai input dan output akan ditampilkan di layar.

Penjelasan

Saya mungkin menggunakan pendekatan yang paling mudah di sini:

  • Minta masukan
  • Membentuk ulang menjadi 5 (baris) x 3 (kolom)
  • Balik urutan baris
  • Ubah posisi matriks untuk menyiapkannya agar dibaca sebagai biner
  • Alokasikan ABC ... XYZ012345 array
  • Bandingkan indeks karakter dari matriks yang ditransposisikan ke huruf kecil yang setara dan konversikan boolean menjadi string, yang kemudian dibaca sebagai biner dan dikonversi menjadi desimal.
  • Menafsirkan desimal ini (bertambah 1) sebagai indeks dari array yang dialokasikan.
  • Tampilkan input dengan 3 karakter tambahan

Sekarang di bawah 100 byte, terima kasih kepada Luis Mendo!

slvrbld
sumber
1
Anda dapat menghemat sedikit menggunakane=['A':'Z',48:53]
Luis Mendo
Saya melihat pendekatan saya hampir sama dengan pendekatan Anda :-)
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;

Tidak berlapis

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

Saya mulai berpikir saya bisa membuatnya lebih pendek dari ini, tetapi saya kehabisan ide untuk membuatnya lebih pendek.

Samsquanch
sumber
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])
TFeld
sumber
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, banyak hal rapi terjadi dalam hal ini. Saya akan mulai dengan baris kedua.

Kami mengambil input sebagai string melalui $args[0]dan mengaturnya $auntuk digunakan nanti. Ini dirangkum dalam ()sehingga dieksekusi dan hasilnya dikembalikan (yaitu, $a) sehingga kita dapat segera menyatukannya dengan hasil dari tiga panggilan fungsi (f ...). Setiap panggilan fungsi dilewatkan sebagai argumen string input diindeks dalam urutan terbalik sebagai char-array - artinya, untuk input contoh,$a[4..0] akan sama @('0','E','R','0','a')dengan setiap entri sebagai char, bukan string.

Sekarang untuk fungsi, di mana daging sebenarnya dari program ini. Kami mengambil input sebagai $f, tetapi hanya digunakan sebagai jalan menuju akhir, jadi mari kita fokus di sana, pertama. Karena ini dilewatkan sebagai char-array (terima kasih untuk pengindeksan kami sebelumnya), kami dapat langsung menyalurkannya ke dalam loop dengan $f|%{...}. Di dalam loop, kita mengambil setiap karakter dan melakukan kecocokan dengan regex case-sensitive -cmatchyang akan menghasilkan true / false jika huruf besar / sebaliknya. Kami melemparkan itu sebagai bilangan bulat dengan enkapsulasi +(), maka array 1 dan 0 adalah -joined untuk membentuk string. Itu kemudian diteruskan sebagai parameter pertama dalam [convert]::ToInt32()panggilan .NET untuk mengubah biner (basis 2) menjadi desimal. Kami menggunakan angka desimal yang dihasilkan untuk mengindeks menjadi string (-join(...)[...]). String pertama kali dirumuskan sebagai rentang (65..90)yang dilemparkan sebagai char-array, kemudian digabungkan dengan rentang (0..5)(yaitu, string tersebut "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"). Semua itu untuk mengembalikan karakter yang sesuai dari string.

AdmBorkBork
sumber
1

Jolf, 30 byte

Akhirnya, mungkin masih bisa disayangi! Coba di sini!

+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
sumber
1

Python 3, 201 174 138 byte

Terima kasih banyak kepada Trang Oul karena telah menunjukkan deklarasi fungsi yang tidak perlu lagi ada. Dan operator ternary Python. Dan beberapa output yang salah. Hanya ... beri dia upvotes.

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
sumber
Anda menggunakan fungsi z()satu kali, Anda dapat mengganti panggilannya dan menghemat 25 byte. Juga, kode Anda salah memberikan [bukan 0.
Trang Oul
Ya, itu adalah kekeliruan yang memalukan di pihak saya. Terima kasih.
Steve Eckert
1
Anda bahkan dapat menghemat lebih banyak dengan mengganti dulu if elsedengan konstruksi ini dan yang kedua dengan operator ternary.
Trang Oul
1

J, 36 byte

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

Pemakaian:

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

Cobalah online di sini.

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

Bekerja untuk input apa pun yang panjangnya kelipatan 5 :)

Tidak disatukan

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
sumber
Untuk menyimpan beberapa byte, Anda dapat menghapus n, dari namespace global jika Anda menggunakan main (n, v, s) untuk tanda tangan Anda karena Anda tidak menggunakan argc.
cleblanc
Juga ganti 26 * 17 dengan 442 tua yang sederhana menghemat byte lain
cleblanc
Dengan beberapa suntingan lagi saya mendapatkan versi Anda hingga 110 byte. Saya tidak mengerti mengapa Anda melakukannya !! isupprer () ketika isupper () tampaknya berfungsi dengan baik untuk saya. Juga saya refactored Anda untuk loop untuk menghapus beberapa yang tidak perlu{} 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 Saran luar biasa, terima kasih banyak. Urutan operasi sangat penting pada n/26*17ekspresi sehingga mengganti dengan 442 bukanlah opsi. Sejauh !!isupper, fungsi itu tidak mengembalikan 1 untuk true pada sistem saya, ia mengembalikan 256. Ini !!adalah cara singkat untuk mengubahnya menjadi nilai pengembalian 0/1 tidak peduli apa. YMMV.
Cole Cameron
1

C #, 171 byte

Saya tidak terlalu terlatih dalam bermain golf C #, tapi ini dia.

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
sumber
Saran: char.IsUpper(t)dapat diganti dengan t>=65&t<=90( &pada bool di C # pada dasarnya adalah golf-pendek &&tanpa hubungan arus pendek). 447lebih pendek dari 26*17. Anda tidak perlu melakukan yang terpisah Select: Anda dapat memasukkan ternary langsung di dalam Sum. Pertimbangkan untuk mengganti semua penggunaan Substringdengan loop berdasarkan Take, misalnya for(int i=0;i<3;i++)s.Skip(i*5).Take(5). Untuk referensi di masa mendatang, u!=""akan lebih pendek dari u.Length>0(tapi itu tidak perlu lagi jika Anda menggunakan Take).
Bob
Ungkapannya n/26*17tidak setara dengan n/442, tetapi selain itu, terima kasih atas sarannya. Seperti yang saya katakan, saya tidak terlalu berpengalaman dalam bermain golf di C # jadi ini semua hal yang bagus untuk saya pertimbangkan di masa depan.
Cole Cameron
Ah, maaf - saya salah membaca itu.
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;}

Jika diminta, saya akan membalikkan kode saya kembali menjadi dapat dibaca dan mempostingnya.

Yytsi
sumber
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))
Aleksi Torhamo
sumber