Преобразовать Salesforce 15-символьный идентификатор в 18-символьный


20

В Salesforce CRM каждый объект имеет 15-символьный буквенно-цифровой идентификатор, который учитывает регистр. Если кому-то интересно, на самом деле это номер базы 62 . Однако инструменты, используемые для переноса и интеграции данных, могут поддерживать или не поддерживать чувствительность к регистру. Чтобы преодолеть это, идентификаторы могут быть безопасно преобразованы в 18-символьные, без учета регистра буквенно-цифровые идентификаторы. В этом процессе трехзначная буквенно-цифровая контрольная сумма добавляется к идентификатору. Алгоритм преобразования:

Пример :

a0RE000000IJmcN
  1. Разделите ID на три 5-символьных блока.

    a0RE0  00000  IJmcN
    
  2. Переверните каждый кусок.

    0ER0a  00000  NcmJI
    
  3. Замените каждый символ в каждом чанке, 1если он в верхнем регистре или 0если в противном случае.

    01100  00000  10011
    
  4. Для каждого 5-значного двоичного числа i, получить символ в положении iв сочетании прописных букв и цифр 0-5 ( ABCDEFGHIJKLMNOPQRSTUVWXYZ012345).

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

    Уступая:

    M  A  T
    
  5. Добавьте эти символы, контрольную сумму, к исходному идентификатору.

Выход :

a0RE000000IJmcNMAT

Напишите программу или функцию, которая принимает 15-символьную буквенно-цифровую (ASCII) строку в качестве ввода и возвращает 18-значный идентификатор.

Проверка входных данных выходит за рамки этого вопроса. Программы могут возвращать любое значение или сбой при неверном вводе.

Пожалуйста, не используйте функцию Salesforce propretiary Языки , которые делают эту задачу тривиальной (например, формулы CASESAFEID(), преобразовывая Idк Stringв APEX & с).

Тестовые случаи

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

3
К сожалению, преобразование строки в Id в Apex Code все равно не будет короче, чем некоторые ответы, представленные здесь, особенно если код должен быть автономным. Apex Code не очень подходит для игры в гольф.
phyrfox

2
@phyrfox как бывший разработчик отдела продаж Апекс не подходит для многих ...
Майк МакМэхон

2
APEX, 56 байт: public class X{public X(Id i){System.debug((String)i);}}. Работает только с действительными идентификаторами Salesforce.
Транг Оул

Я пришел сюда, чтобы на самом деле сделать это для работы ( success.jitterbit.com/display/DOC/… ) , а не для гольфа, но меня немного смущает описание алгоритма. Вы говорите, что каждый перевернутый и продезинфицированный кусок на шаге 4 будет «двоичным числом», но вы никогда не заменяете цифры 2-8 на 0 и 1. Что именно я должен сделать для шага 4, когда шаги 1-3 на чанке типа «62mPg» привели к числу, например «01026»?
к ..

Ответы:


6

Рубин, 97 байт

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

У этого есть некоторые действительно аккуратные уловки.

Мой оригинальный инстинкт для разделения строки на группы из 5 символов был 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]]

Оказывается, это слишком долго по сравнению с простым регулярным выражением ( x.chars.each_slice(5)против x.scan(/.{5}/)). Оглядываясь назад, это кажется очевидным, но я никогда не задумывался об этом ... возможно, я могу оптимизировать некоторые из моих старых ответов Ruby здесь.

Однако в этом ответе я больше всего горжусь этим фрагментом кода:

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

Хорошо, так что вот немного предыстории для нерубистов. Ruby полностью отделяет логические значения ( TrueClass, FalseClass) от целых чисел / (Numeric ) - это означает, что нет автоматического преобразования из true в 1 и из false в 0. Это раздражает во время игры в гольф (но это хорошо ... для всех других целей).

Наивный подход к проверке, является ли единственный символ заглавными (и возвращает 1 или 0),

y.upcase==y?1:0

Мы можем получить это немного дальше (опять же, с помощью регулярного выражения):

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

Но потом я действительно начал думать. Хм ... =~возвращает индекс совпадения (то есть для нашего отдельного символа, всегда, 0если совпадение есть) или, nilесли совпадение не найдено, ложное значение (все остальное, кроме FalseClassправдоподобного в Ruby). ||Оператор берет свой первый операнд , если это truthy, а его второй операнд в противном случае. Поэтому мы можем сыграть в гольф до

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

Хорошо, давайте посмотрим на то, что здесь происходит. Если yэто заглавная буква, она не будет соответствовать [^A-Z], поэтому часть регулярного выражения вернется nil. nil || 1есть 1, поэтому заглавные буквы становятся 1. Если yэто что-то, кроме заглавной буквы, часть регулярного выражения вернется 0(потому что в индексе есть совпадение 0), и, поскольку 0это правда, 0 || 1есть 0.

... и только после записи всего этого я понимаю, что это на самом деле такая же длина, как y=~/[A-Z]/?1:0. Хаха, да ладно.


6

Pyth, 23 22 байта

1 байт сохранен FryAmTheEggman .

sm@s+JrG1U6i}RJ_d2c3pz

Попробуйте онлайн. Тестирование.

Это может быть первый раз, когда я использовал pинструкцию по игре в гольф.

объяснение

     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 байта

j1Y24Y2hG5IePtk=~!XB1+)h

Использует текущую версию (9.1.0) языка / компилятора.

Примеры

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

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

объяснение

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

Тестовое задание

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 байт

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

Запустите все тестовые случаи.

Довольно простая реализация спецификации. Самая интересная часть - это преобразование символов в контрольную сумму. Мы добавляем 17 к результату каждого куска. Возьми это по модулю 43 и добавь результат этого к персонажу '0.



2

JavaScript (ES6), 137 132 байта

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

4 байта сохранены благодаря @ ՊՓԼՃՐՊՃՈԲՍԼ !

объяснение

Эта задача совсем не подходит для JavaScript. Нет короткого способа перевернуть строку, и похоже, что самый короткий способ преобразовать число в символ - это жестко закодировать каждый возможный символ.

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

Если бы цифры в контрольной сумме были разрешены в нижнем регистре, это могло бы быть сделано в 124 байтах следующим образом:

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

Тестовое задание


Если я не ошибаюсь, parseInt([...n].reverse().join``,2)можно изменить на +`0b${[...n].reverse().join``}`.
Mama Fun Roll

@ ՊՓԼՃՐՊՃՈԲՍԼ Ты прав! Я сохранил еще один байт, спасибо.
user81655

Сохранить 10 целых байтов с помощью .replace(/.{5}/g,n=>/*stuff*/).
Нил

2

MATLAB, 100 98 байт

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

В качестве входных данных будет запрошена строка, а выходные данные будут отображены на экране.

объяснение

Я, наверное, использую самый простой подход здесь:

  • Запросить ввод
  • Изменить до 5 (строки) х 3 (столбцы)
  • Отразить порядок строк
  • Транспонировать матрицу, чтобы подготовить ее к чтению в двоичном виде
  • Выделите массив ABC ... XYZ012345
  • Сравните индексы символов транспонированной матрицы с ее строчными эквивалентами и преобразуйте логические значения в строки, которые затем читаются как двоичные и преобразуются в десятичные.
  • Интерпретировать эти десятичные дроби (с шагом 1) как индексы выделенного массива.
  • Отображение ввода с дополнительными 3 символами

Теперь ниже 100 байтов благодаря Луису Мендо!


1
Вы можете сэкономить немного, используяe=['A':'Z',48:53]
Луис Мендо

Я вижу, что мой подход почти такой же, как ваш :-)
Луис Мендо

2

PHP, 186 181 байт

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

Я начал с того, что думал, что смогу сделать его намного короче, но у меня не осталось идей сделать его короче.


1

Python 2, 97 байт

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 байта

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

ОК, в этом много чего интересного. Я начну со второй строки.

Мы принимаем ввод как строку через $args[0]и устанавливаем его $aдля использования позже. Он инкапсулирован ()так, что он выполняется и возвращается результат (т. Е. $a), Поэтому мы можем сразу же объединить его с результатами трех вызовов функций (f ...). Каждый вызов функции передает в качестве аргумента входную строку, индексированную в чанках в обратном порядке, как массив символов - значение для входного примера $a[4..0]будет равно@('0','E','R','0','a') каждой записи как символ, а не строка.

Теперь о функции, где настоящее мясо программы. Мы воспринимаем ввод как $f, но он используется только ближе к концу, поэтому давайте сначала сосредоточимся на этом. Поскольку он передается как массив символов (благодаря нашей предыдущей индексации), мы можем немедленно передать его в цикл с помощью $f|%{...}. Внутри цикла мы берем каждый символ и выполняем регистрозависимое совпадение с учетом регистра, -cmatchкоторое приводит к значению true / false, если оно прописное / в противном случае. Мы приводим это как целое число к инкапсуляции +(), затем этот массив из 1 и 0 -joinредактируется для формирования строки. Это затем передается в качестве первого параметра в .NET который приводится как массив символов, а затем объединяется с диапазоном[convert]::ToInt32() вызова , чтобы изменить двоичный (базовый 2) в десятичной системе . Мы используем это результирующее десятичное число для индексации в строку (-join(...)[...]). Строка сначала формулируется как диапазон(65..90)(0..5)(то есть строка "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"). Все это - вернуть соответствующий символ из строки.


1

Джольф, 30 байт

Наконец-то, вероятно, все еще в шутку! Попробуй это здесь!

+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 байт

Большое спасибо Trang Oul за указание на объявление функции, которая больше не нужна. И Python троичные операторы. И какой-то неверный вывод. Просто ... просто отдай ему голоса.

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)

Вы используете функцию z()один раз, вы можете заменить ее вызов и сохранить 25 байтов. Кроме того, ваш код неправильно назначает [вместо 0.
Транг Оул

Ну, это было смущающее упущение с моей стороны. Благодарю.
Стив Экерт

1
Вы можете сэкономить еще больше, заменив первый if elseна эту конструкцию, а второй на троичный оператор.
Транг Оул


1

C, 120 118 байт

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

Работает для любого входа, длина которого кратна 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);
    }
}

Чтобы сохранить несколько байтов, вы можете удалить n из глобального пространства имен, если вы используете main (n, v, s) для своей подписи, так как иначе вы не используете argc.
cleblanc

Также замените 26 * 17 простым старым, 442 сохраняет другой байт
cleblanc

С помощью еще нескольких правок я сократил вашу версию до 110 байт. Я не понимаю, почему у вас был !! isupprer (), когда isupper (), кажется, работает нормально для меня. Также я реорганизовал ваши циклы for, чтобы удалить некоторые ненужные{} 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 Отличные предложения, большое спасибо. Порядок операций очень важен для n/26*17выражения, поэтому замена на 442 не вариант. Поскольку !!isupperэта функция не возвращает 1 для true в моей системе, она возвращает 256. Это !!короткий способ преобразовать его в возвращаемое значение 0/1, несмотря ни на что. YMMV.
Коул Кэмерон

1

C #, 171 байт

Я не очень хорошо практиковался в игре в гольф на C #, но здесь есть шанс.

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

Предложения: char.IsUpper(t) могут быть заменены на t>=65&t<=90( &на bool в C # это в основном гольф-короче &&без короткого замыкания). 447короче чем 26*17. Вам не нужно делать отдельное Select: вы можете включить троичный непосредственно в Sum. Попробуйте заменить все эти использования Substringцикла на основе Take, например, например for(int i=0;i<3;i++)s.Skip(i*5).Take(5). Для дальнейшего использования u!=""будет короче u.Length>0(но это больше не нужно, если вы используете Take).
Боб

Выражение n/26*17не эквивалентноn/442 , но кроме этого, спасибо за предложения. Как уже говорилось, я не очень разбираюсь в гольфе в C #, так что это все, что я должен рассмотреть в будущем.
Коул Кэмерон

Ах, прости - я неправильно это понял.
Боб

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

Если потребуется, я верну свой код обратно для чтения и опубликую его.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.