# Japanese Encoding Conversion

### Background

In JIS X 0208 a 94 by 94 map (kuten (区点)) is defined to encode Chinese characters (kanji), phonetic moras (kana) and other symbols. Along with this standard there are 3 different encodings that maintain 1-1 correspondences with the map, namely JIS, Shift_JIS and EUC. These encodings take 2 bytes for each character in the kuten map. The mappings are different that random characters may occur (mojibake) if the wrong encoding is used.

### Conversion Algorithm

In the formulae below, kuten is an ordered pair of numbers $$\(区,点)\$$ where $$\1\le 区,点\le94\$$, and $$\(a,b)\$$ is an ordered pair of bytes where $$\0\le a,b\le 255\$$. The conversions between kuten and the 3 encodings are as follows:

$$\text{JIS}: (a,b)=(32+区,32+点)$$

$$\text{Shift_JIS}: (a,b)=\begin{cases} \left(128+\left\lceil\frac{区}{2}\right\rceil+64\left\lfloor\frac{区}{63}\right\rfloor,63+点+\left\lfloor\frac{点}{64}\right\rfloor\right)&\text{if }区\text{ is odd}\\ \left(128+\left\lceil\frac{区}{2}\right\rceil+64\left\lfloor\frac{区}{63}\right\rfloor,158+点\right)&\text{if }区\text{ is even} \end{cases}$$

$$\text{EUC}: (a,b)=(160+区,160+点)$$

### Challenge

Write a program or function that, given a byte pair, the source encoding and the destination encoding, converts the byte pair from the source encoding to the destination encoding and outputs the result. You may assume that the input byte pair represents a valid codepoint in the source encoding.

The input and output formats are flexible and are accepted if reasonable. For example, you may receive or output the byte pair as a list, as two numbers or as a number, either in decimal or hexadecimal; you may also assign a number to each of the possible encodings and use them as the input format of the encodings.

### Sample IO

The format used in the samples is SrcCodePoint, SrcEncoding, DstEncoding -> DstCodePoint. Decimal is used here but hexadecimal is also acceptable. The Unicode character and its assigned kuten are for explanation.

(227, 129), Shift_JIS, EUC -> (229, 225) (Kuten: 69-65; U+7E3A 縺)
(101, 98), JIS, Shift_JIS  -> (227, 130) (Kuten: 69-66; U+7E67 繧)
(229, 227), EUC, JIS       -> (101, 99)  (Kuten: 69-67; U+7E5D 繝)
(137, 126), Shift_JIS, JIS -> (49, 95)   (Kuten: 17-63; U+5186 円)
(177, 224), EUC, Shift_JIS -> (137, 128) (Kuten: 17-64; U+5712 園)
(49, 97), JIS, EUC         -> (177, 225) (Kuten: 17-65; U+5830 堰)


See here (in Japanese) for the full table.

### Winning condition

This is a code-golf challenge, so the shortest valid submission for each language wins. Standard loopholes are forbidden by default.

• See my answer; since this codepoint stuff is technically specific to Extended Unix Code - Japanese (EUC-JP) instead of the standard EUC, could I possibly require that as an input? :) Mar 9, 2020 at 9:16
• @ValueInk Yes you may treat EUC as EUC-JP in this challenge. Mar 9, 2020 at 9:50

# Ruby, 140 116 bytes

Takes code point as an array, and encodings are JIS, Shift_JIS, and EUC-JP, respectively.

Ruby supports converting between EUC-JP and SHIFT_JIS, so we math JIS encoding into EUC, perform the appropriate conversion, then math back the JIS encoding if that's the destination encoding.

-34 bytes by getting permission to take EUC input as EUC-JP.

->c,s,d{(c.map!{|e|e+=128};s="EUCJP")if s=~r=/^J/
c.pack('c*').encode(d[r]?"EUCJP":d,s).bytes.map{|e|e-=d[r]?128:0}}


Try it online!

Explanation

->c,s,d{                                            # Function that takes 3 parameters
(                           )if s=~r=/^J/   # If s is JIS: (starts with J)
#  (also store this regex for later)
c.map!{|e|e+=128};                         # Add 128 to each codepoint
s="EUCJP"                # Change s to EUC-JP locale
c.pack('c*')                                      # Pack codepoints into bytestring
.encode(                                        # Encode the bytestring as follows:
#  Destination encoding is:
d[r]?"EUCJP":d,                               #   If d is JIS, use EUC-JP instead
s                                             #  Source encoding
)
.bytes                                          # Convert to bytes
.map{|e|e-=d[r]?128:0}                          # If d is JIS, subtract 128
}


### Pure Math Version, 164 162 bytes

Takes code points separately, and the encodings are integers: 0=JIS, 1=SHIFT_JIS, 2=EUC.

-2 bytes from Jonathan Allen.

->a,b,s,d,e=160{k,t=[[a-32,b-32],[a*2-1+b/158-(2+a/222)*128,b-63-b/128-b/158*94],[a-e,b-e]][s]
[[k+32,t+32],[128+k/2+k%2+k/63*64,158+t+t/64-k%2*95],[k+e,t+e]][d]}


Try it online!

• c=160; should save you 2 in the pure maths version. Mar 9, 2020 at 10:40

# 05AB1E, 37 34 bytes

93ÝãDžy+∞x64&+₃+Ƶ₁L64K30+â)33+Iè‡


First input is [source encoding, destination encoding], with 0 representing JIS, 1 for EUC, and 2 for ShiftJIS.

Second input it [byte pair].

# Jelly, 62 bytes

Tired & ill so probably very beatable!

⁹:64;95⁸ị+63+
‘&64+HƲḞ+Ø⁷,ç
94,þ“¡ ɦ‘+€ç/€€€1¦
Ḣị¢⁼€€ŒṪṪ⁸;œị¢


A dyadic Link accepting [SrcEncoding, DstEncoding] on the left and SrcCodePoint on the right which yields DstCodePoint.

Where SrcEncoding and DstEncoding are:

Shift_JIS  1
JIS  2
EUC  3


Try it online! Or see the test-suite.

# JavaScript (Node.js), 172 bytes

(a,b,x,y)=>eval('for(c=d=t=0;c-a|b-d;[c,d]=x(p,q))y(p=++t>>8,q=t&255)')
S=(k,t)=>[128+k/2+k%2/2+64*(k>62),(k%2?63+(t>63):158)+t]
J=(k,t)=>[32+k,32+t]
E=(k,t)=>[160+k,160+t]


Try it online!

Invoke as f(227, 129, S, E) where S=Shift_JIS, E=EUC, J=JIS.

• You should be allowed to take arguments separately. (a,b,x,y)=> for -2 bytes. Mar 9, 2020 at 10:48

# Clojure, 51 50 bytes

#(for[b(.getBytes(String. %2%)%3)](bit-and b 255))


Try it online!

Anonymous function taking three arguments: source encoding, input pair as a Java byte array, and destination encoding.

This relies on JVM's built-in conversion functionality. As other answers are doing, I took the liberty to modify the expected encoding strings to match the format recognized by the JVM:

• JIS -> JIS0208 (Simply "JIS" is also listed in Java docs, but somehow doesn't work)
• Shift_JIS remains as is
• EUC -> EUC-JP

x?(a,b)=[(a+32,b+32),(128+div a 2+rem a 2+64*div a 63,b+63+[95,div b 64]!!rem a 2),(a+160,b+160)]!!x