10
\$\begingroup\$

The objective

Given a Russian text, encrypt it with Caesar cipher with key 16.

The basic Cyrillic alphabets

The basic Cyrillic alphabets are: (U+0410 – U+042F)

АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ

By the Caesar cipher, they are mapped to:

РСТУФХЦЧШЩЪЫЬЭЮЯАБВГДЕЖЗИЙКЛМНОП

The small letters (U+0430 – U+044F) are also mapped likewise.

Note the absence of Ё.

Rules

  1. Ё (U+0401) and ё (U+0451) are not considered basic, and are mapped to Х̈ (U+0425 U+0308) and х̈ (U+0445 U+0308), respectively.

  2. Any other characters are preserved.

Example

The following sentence:

В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!

Is encrypted to:

Т зрйре оур цшы сл жшвагб? Фр, эю дрымиштлщ нъчхьяыпа!
\$\endgroup\$
  • \$\begingroup\$ We only have to map Ё and ё to Х̈ and х̈, right? And not also the reverse from X/x to E/e? \$\endgroup\$ – Kevin Cruijssen Oct 10 at 7:41
  • \$\begingroup\$ @Kevin Cruijseen Since Х̈ doesn't exist in Russian, it falls in don't care situation. \$\endgroup\$ – Dannyu NDos Oct 10 at 8:03
  • \$\begingroup\$ Are all non-Cyrillic characters in the input guaranteed to be standard ASCII? (32-126) \$\endgroup\$ – Arnauld Oct 10 at 8:51
  • 8
    \$\begingroup\$ Your answer to @KevinCruijssen should probably be included as a short comment in the challenge to make this perfectly clear. (My initial version was converting x/X + diaeresis to E/e + diaeresis.) \$\endgroup\$ – Arnauld Oct 10 at 15:25
  • 5
    \$\begingroup\$ That's far too soon to be accepting a solution. \$\endgroup\$ – Shaggy Oct 10 at 20:46
5
\$\begingroup\$

05AB1E, 16 40 39 33 bytes

63ÝD16^‚Ž4K+ç`‡•2.w2γ•3äçDl‚vy`«:

Would be just the first 15 bytes without the edge case of mapping Ёё to Х̈х̈.

-7 bytes thanks to @Grimy.

Try it online.

Explanation:

63Ý              # Push a list in the range [0,63]
   D             # Duplicate it
    16^          # Bitwise-XOR each value with 16: [16..31, 0..15, 48..63, 33..47]
        ‚        # Pair it with the initial [0,63] list we duplicated
         Ž4K     # Push compressed integer 1040
            +    # Add it to each integer in the inner lists
             `   # Push both lists separated to the stack again
              ‡  # Transliterate the characters in the first list to the second list
                 # in the (implicit) input-string
•2.w2γ•          # Push compressed integer 10251061776
       3ä        # Spit it into three parts: [1025,1061,776]
         ç       # Convert each to a character: ["Ё","Х","̈"]
Dl               # Create a lowercase copy: ["ё","х","̈"]
  ‚              # Pair them together: [["Ё","Х","̈"],["ё","х","̈"]]
   v             # Loop over both these lists `y`:
    y`           #  Push the characters of the current list separated to the stack
      «          #  Append the top two together: Х̈/х̈
       :         #  And replace the Ё/ё with Х̈/х̈ in the (modified) input-string
                 # (after which the result is output implicitly)

See this 05AB1E tip of mine (section How to compress large integers?) to understand why Ž4K is 1040 and •2.w2γ• is 10251061776.

\$\endgroup\$
  • \$\begingroup\$ Undealt with Ё. \$\endgroup\$ – Dannyu NDos Oct 10 at 7:33
  • \$\begingroup\$ @DannyuNDos Fixed (at the cost of 24 bytes.. >.>) \$\endgroup\$ – Kevin Cruijssen Oct 10 at 8:28
  • 2
    \$\begingroup\$ The first part can be 63ÝD16^‚Ž4K+ç`‡ for -1. It's a shame doesn't work on cyrillic letters (even though u and l do), that would save a lot. \$\endgroup\$ – Grimy Oct 10 at 14:34
  • 2
    \$\begingroup\$ @Grimy Hmm, sounds like something to report as a bug. And thanks for the -1. Nice approach with the XOR 16 \$\endgroup\$ – Kevin Cruijssen Oct 10 at 14:47
  • 2
    \$\begingroup\$ And the second part can be •2.w2γ•3äçDl‚vy`«: for -6. \$\endgroup\$ – Grimy Oct 10 at 14:55
6
\$\begingroup\$

JavaScript (ES6),  148 ... 110  108 bytes

Saved 12 bytes thanks to @Grimy!

This function applies some maths to the code points.

s=>s.replace(/./g,s=>String.fromCharCode(...(n=s.charCodeAt()-304)%80-1?[(n^16*(n>0))+304]:[1060+n%48,776]))

Try it online!

How?

For each character in the input string, we define \$n\$ as its code point minus \$304\$.

 characters    | code points  | n
---------------+--------------+---------------
 А to Я        | 1040 to 1071 | 736 to 767
 а to я        | 1072 to 1103 | 768 to 799
 Ё             | 1025         | 721
 ё             | 1105         | 801
 ASCII         | 0 to 126     | -304 to -178

Then we apply the following logic:

// neither 'Ё' nor 'ё'?
n % 80 - 1 ?
  // output a single code point
  [
    // invert the case if this is a Cyrillic character
    (n ^ 16 * (n > 0))
    // and restore the original offset
    + 304
  ]
:
  // output two code points
  [
    // the first one is either 1061 (Х) or 1093 (х)
    1060 + n % 48,
    // the 2nd one is the combining diaeresis
    776
  ]
\$\endgroup\$
  • \$\begingroup\$ 110 with some bitwise magic \$\endgroup\$ – Grimy Oct 10 at 15:36
  • 1
    \$\begingroup\$ Easy fix, still 110 \$\endgroup\$ – Grimy Oct 10 at 16:20
  • \$\begingroup\$ @Grimy Would you like to post it as a separate answer? \$\endgroup\$ – Arnauld Oct 10 at 16:22
  • \$\begingroup\$ No, I'm fine, thanks. \$\endgroup\$ – Grimy Oct 10 at 16:24
5
\$\begingroup\$

Retina 0.8.2, 41 bytes

T`А-Па-пя-рЯ-Р`Ro
Ё
Х̈
ё
х̈

Try it online! Just a transliteration and a fixup of the two special cases. The characters to be transliterated are listed in mirror order so that Ro can be used to specify the reverse order for the transliteration.

\$\endgroup\$
  • \$\begingroup\$ seems works without ё case 22 bytes \$\endgroup\$ – Nahuel Fouilleul Oct 10 at 10:42
  • \$\begingroup\$ @NahuelFouilleul That's not a U+0451 that you've got there... \$\endgroup\$ – Neil Oct 10 at 10:46
  • \$\begingroup\$ ok it was composed character, my bad, this is why it was working \$\endgroup\$ – Nahuel Fouilleul Oct 10 at 10:57
  • \$\begingroup\$ seems number of bytes not up to date isn't 27 \$\endgroup\$ – Nahuel Fouilleul Oct 10 at 11:10
  • \$\begingroup\$ @NahuelFouilleul Unfortunately TIO always assumes I'm using ISO-8859-1 (most Retina programs do) but here I'm using UTF-8 so I have to count it in UTF-8 bytes. \$\endgroup\$ – Neil Oct 10 at 22:13
3
\$\begingroup\$

Perl 5 (-pC -Mutf8 -MUnicode::Normalize=NFD), 37 bytes (27 chars)

$_=NFD$_;y;А-я;Р-ЯА-Пр-яа-п

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Does it work in Perl 6? \$\endgroup\$ – Dannyu NDos Oct 10 at 10:44
  • \$\begingroup\$ I don't know perl 6, 40 bytes ->52 bytes because there was an issue with ё instead of ё in input \$\endgroup\$ – Nahuel Fouilleul Oct 10 at 11:01
3
\$\begingroup\$

Red, 236 166 bytes

func[s][rejoin collect[foreach c s[keep
case[c =#"Ё"["Х̈ "]c =#"ё"["х̈"]c < #"А"[c]any[c > #"Џ"c < #"ѐ"][(pick[#"А"#"а"]c < #"а")+ to 1 c - 1024 % 32]]]]]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

PHP (7.4), 199 chars, 333 bytes

<?=strtr($argn,array_combine(($s=str_split)(АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяёЁ,2),[...$s(РСТУФХЦЧШЩЪЫЬЭЮЯАБВГДЕЖЗИЙКЛМНОПрстуфхцчшщъыьэюяабвгдежзийклмноп,2),х̈,Х̈ ]));

Try it online!

Just a string replacement.

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 103 102 101 bytes

-join$(switch -c($args){Ё{'Х̈'}ё{'х̈'}default{[char](2*(($_-band16)-8)*($_-in1040..1103)+$_)}})

Try it online!

This script takes a splatted string. Unrolled:

-join$(
    switch -CaseSensitive ($args){
        Ё{'Х̈'}
        ё{'х̈'}
        default {
            $offset  = 2*(($_ -band 16)-8) # -band is 'Bitwise AND'
            $offset *= ($_ -in 1040..1103) # is basic Cyrillic alphabet?
            [char]($offset+$_)

        }
    }
)
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 53 bytes

FS¿⁼Ё↥ι⁺§хХ⁼Ёϊ¿№…А¦ѐι℅⁺℅ι⎇‹↥ιР¹⁶±¹⁶ι

Try it online! Link is to verbose version of code. Explanation:

FS

Loop over the characters in the input.

¿⁼Ё↥ι

If the uppercase is equal to Ё...

⁺§хХ⁼Ёϊ

... then print the appropriate х or Х with its combining character...

¿№…А¦ѐι

... otherwise if it's a Cyrillic letter...

℅⁺℅ι⎇‹↥ιР¹⁶±¹⁶

... do some maths on its ordinal to create the character to output...

ι

... otherwise output the input character.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.