2014-10-28 2 views
3

아랍어로 "سلام"인 "0633064406270645"와 같은 UTF-16 16 진수 표현이 있습니다.UTF16 16 진수 - 텍스트

해당 텍스트로 변환하고 싶습니다. PostgreSQL에서 바로 할 수 있습니까?

아래와 같이 UTF 코드 포인트를 변환 할 수 있습니다. 불행히도 그것은 UTF16 지원되지 않는 것 같습니다. PostgreSQL에서 수행하는 방법에 대한 아이디어는 최악의 경우 함수를 작성하겠습니까?

SELECT convert_from (decode (E'D8B3D984D8A7D985', 'hex'),'UTF8'); 

"سلام" 

SELECT convert_from (decode (E'0633064406270645', 'hex'),'UTF16'); 

ERROR: invalid source encoding name "UTF16" 
********** Error ********** 
+0

두 기술 모두 잘 작동합니다. 유니 코드 이스케이프 시퀀스를 사용하는 것보다 함수가 정확 해 보입니다. 내 응용 프로그램의 경우 정확성이 필요하지 않으므로 두 가지 기술이 모두 필요합니다. – Adam

답변

2

맞습니다. Postgres는 UTF-16을 지원하지 않습니다.

그러나, 지원 Unicode escape sequences 수행합니다

SELECT U&'\0633\0644\0627\0645' 

을하지만 유니 코드 코드 포인트UTF-16 코드 단위Basic Multilingual Plane 만 동일하다는 것을 명심하십시오. 즉, 여러 개의 16 비트 코드 단위에 걸쳐있는 UTF-16 문자가있는 경우 직접 해당 코드 포인트로 변환해야합니다.

2

convert_from (또는 일반적으로 PostgreSQL)은 UTF-16을 지원하지 않지만 선택 가능한 언어 중 하나에 의존 할 수 있습니다. plperlu에서

예 (이미 생성되어 있지 않은 경우 함수를 만드는 데이터베이스 수퍼 유저 권한이 필요하고, CREATE LANGUAGE plperlu) :

CREATE FUNCTION decode_utf16(text) RETURNS text AS $$ 
    require Encode; 
    return Encode::decode("UTF-16BE", pack("H*", $_[0])); 
$$ immutable language plperlu; 

=> select decode_utf16('0633064406270645'); 

decode_utf16 
-------------- 
سلام 
1

의 PostgreSQL은 기본적으로 UTF-16을 지원하지 않습니다. DB에 공급하기 전에 데이터를 UTF-8로 변환하는 것이 좋습니다. 모든 변환 할 수 있습니다, 이러한 기능으로

-- convert from bytea, containing UTF-16-BE data 
CREATE OR REPLACE FUNCTION convert_from_utf16be(utf16_data bytea, invalid_replacement text DEFAULT '?') 
    RETURNS text 
    LANGUAGE sql 
    IMMUTABLE 
    STRICT 
AS $function$ 
WITH source(unit) AS (
    SELECT (get_byte(utf16_data, i) << 8) | get_byte(utf16_data, i + 1) 
    FROM generate_series(0, octet_length(utf16_data) - 2, 2) i 
), 
codes(lag, unit, lead) AS (
    SELECT lag(unit, 1) OVER(), unit, lead(unit, 1) OVER() 
    FROM source 
) 
SELECT string_agg(CASE 
    WHEN unit >= 56320 AND unit <= 57343 THEN CASE 
    WHEN lag >= 55296 AND lag <= 56319 THEN '' -- already processed 
    ELSE invalid_replacement 
    END 
    WHEN unit >= 55296 AND unit <= 56319 THEN CASE 
    WHEN lead >= 56320 AND lead <= 57343 THEN chr((unit << 10) + lead - 56613888) 
    ELSE invalid_replacement 
    END 
    ELSE chr(unit) 
END, '') 
FROM codes 
$function$; 

-- convert from bytea, containing UTF-16-LE data 
CREATE OR REPLACE FUNCTION convert_from_utf16le(utf16_data bytea, invalid_replacement text DEFAULT '?') 
    RETURNS text 
    LANGUAGE sql 
    IMMUTABLE 
    STRICT 
AS $function$ 
WITH source(unit) AS (
    SELECT get_byte(utf16_data, i) | (get_byte(utf16_data, i + 1) << 8) 
    FROM generate_series(0, octet_length(utf16_data) - 2, 2) i 
), 
codes(lag, unit, lead) AS (
    SELECT lag(unit, 1) OVER(), unit, lead(unit, 1) OVER() 
    FROM source 
) 
SELECT string_agg(CASE 
    WHEN unit >= 56320 AND unit <= 57343 THEN CASE 
    WHEN lag >= 55296 AND lag <= 56319 THEN '' -- already processed 
    ELSE invalid_replacement 
    END 
    WHEN unit >= 55296 AND unit <= 56319 THEN CASE 
    WHEN lead >= 56320 AND lead <= 57343 THEN chr((unit << 10) + lead - 56613888) 
    ELSE invalid_replacement 
    END 
    ELSE chr(unit) 
END, '') 
FROM codes 
$function$; 

-- convert from bytea, containing UTF-16 data (with or without BOM) 
CREATE OR REPLACE FUNCTION convert_from_utf16(utf16_data bytea, invalid_replacement text DEFAULT '?') 
    RETURNS text 
    LANGUAGE sql 
    IMMUTABLE 
    STRICT 
AS $function$ 
SELECT CASE COALESCE(octet_length(utf16_data), 0) 
    WHEN 0 THEN '' 
    WHEN 1 THEN invalid_replacement 
    ELSE CASE substring(utf16_data FOR 2) 
    WHEN E'\\xFFFE' THEN convert_from_utf16le(substring(utf16_data FROM 3), invalid_replacement) 
    ELSE convert_from_utf16be(substring(utf16_data FROM 3), invalid_replacement) 
    END 
END 
$function$; 

: 그것은 (잘못된 데이터가 이미 DB에 존재하는) 너무 늦은 경우, UTF-16 (wikipedia에서 복사 로직)에서 데이터를 변환하기 위해 이러한 유지 보수 기능을 사용할 수 있습니다 UTF-16 종류 :

SELECT convert_from_utf16be(decode('0633064406270645D852DF62', 'hex')), 
     convert_from_utf16le(decode('330644062706450652D862DF', 'hex')), 
     convert_from_utf16(decode('FEFF0633064406270645D852DF62', 'hex')), 
     convert_from_utf16(decode('FFFE330644062706450652D862DF', 'hex')); 

-- convert_from_utf16be | convert_from_utf16le | convert_from_utf16 | convert_from_utf16 
------------------------+----------------------+--------------------+------------------- 
-- سلام    | سلام    | سلام    | سلام