2011-10-21 3 views
0

웹 양식 (Perl 스크립트 사용)을 통해 수집 된 8859 형식으로 저장되어있는 텍스트 문서의 적당한 크기의 플랫 파일 데이터베이스가 있습니다. 최근까지 내가 정규식의 간단한 세트 일반 1,252 문자 (둥근 따옴표, 작은 따옴표 등)을 협상했다 최대 : 내가 결정 이후Perl에서 utf8 모드로 열어 본 ASCII 텍스트 파일 중 1252자를 필터링합니다.

$line=~s/\x91/\&\#8216\;/g; # smart apostrophe left 
$line=~s/\x92/\&\#8217\;/g; # smart apostrophe right 

... 등등 그러나

내가가는되어야한다 유니 코드를 사용하고 모든 스크립트를 변환하여 utf8 (모든 새 머티리얼에 대한 처리를 수행함)을 출력하면이 (기존) 1252 문자에 대한 정규 표현식이 더 이상 작동하지 않고 Perl html 출력이 문자 ' x92 '와'\ x93 '등 (적어도 utf8 모드에서 브라우저에 나타나는 방법 (http가 아닌 ftp)을 다운로드하고 텍스트 편집기 (textpad)에서 열기, 정의되지 않은 단일 문자가 남아서 Firefox의 기본 출력 파일 (콘텐츠 형식 헤더 없음) 8859 모드는 올바른 문자를 렌더링합니다.

스크립트의 시작에 새로운 UTF8 프라그 마를

은 다음과 같습니다

사용 CGI의 QW (-utf8); 오픈 IO 사용 => ': utf8';

이것은 utf8 모드로 인해 문자가 1 바이트가 아닌 2 바이트로되어 있고 0x80에서 0xff 범위의 문자에 적용된다는 것을 이해합니다. 이에 대해서는 wikibooks 관련 기사를 읽었지 만 나는 현명하지 않았습니다. 그들을 필터링하는 방법에 관해서. 이상적으로 나는 평범한 파일 데이터베이스가 이제 8859와 utf8의 혼합을 포함하고 있기 때문에 모든 문서를 utf8 모드로 다시 저장해야한다는 것을 알고 있습니다. 그러나 어쨌든이 작업을 수행하려면 먼저 필터를 사용해야합니다. .

그리고 내부적으로 2 바이트 스토리지에 관해서는 잘못된 것일 수 있습니다. Perl이 다양한 상황에 따라 매우 다르게 처리한다는 것을 암시하는 것처럼 보였기 때문입니다.

누구든지 정규식 솔루션을 제공 할 수 있다면 매우 감사 할 것입니다. 아니면 다른 방법. 나는 여러 가지 시도와 해킹 실패로 몇 주 동안 머리카락을 찢어 버렸다. 일반적으로 대체해야 할 약 6,1252 자 정도의 문자가 있습니다. 필터 방법을 사용하면 utf8에서 전체 재봉틀을 다시 저장하고 1252가 잊어 버릴 수 있습니다.

+0

아 ... 그리고는 DB 지금 UTF8과 8859 으악를 포함하고 있기 때문에 8859 및 필터에서 파일을 열 단지 재설정 할 수 없습니다. – Beeblbrox

답변

1

Ikegami already mentionedEncoding::FixLatin 모듈.각 문자열이 될 것이라고 알고 있다면

또 다른 방법은 그것을 할 UTF-8 또는 CP1252 있지만 둘의 혼합물, 이진 문자열로 읽고하는 것입니다 :

unless (utf8::decode($string)) { 
    require Encode; 
    $string = Encode::decode(cp1252 => $string); 
} 

Encoding :: FixLatin과 비교하면 다음과 같은 두 가지 장점이 있습니다. 전체 문자열이 유효한 UTF-8이어야하므로 CP1252 텍스트를 UTF-8로 오인 할 확률이 약간 낮고 CP1252를 다른 대체 인코딩으로 대체 할 가능성 . 해당 단점은이 코드가 멀티 바이트 문자의 중간에서 잘 렸기 때문에 다른 이유로 인해 완전히 유효한 UTF-8이 아닌 문자열에서 CP1252로 폴백 할 수 있다는 것입니다.

+0

멋진 해결책이 될 것입니다. 내가 전체 파일을 하나 또는 다른 것으로 털어 버리는 것이 아니라 줄 단위로 디코딩하는 것이다. 그래서 이것은 유효한 utf8 문자열을 혼자 남겨두고 이전처럼 정규 표현식을 사용하여 비 utf 문자를 포함하는 문자열로 주위를 망칠 수 있습니까? – Beeblbrox

+0

... 그리고 정확히 내가 뭘 찾고있는 것 같아 hte FixLatin 모듈에 대해 몰랐어요, 덕분에 다시 – Beeblbrox

+0

둘 다 이러한 솔루션은 (charset misidentification의 작은 기회를 제외하고) Perl로 모든 입력 문자열을 변환합니다 UTF-8 또는 CP1252로 인코딩되었는지 여부에 관계없이 유니 코드 문자열 (내부적으로 UTF-8로 표시 될 수 있지만 실제로는 신경 쓰지 않아야 함). 따라서 그 위에 "정규식 제거"를 추가로 수행 할 필요가 없습니다. (비록 그 정규 표현식이 유효한 인쇄 가능한 유니 코드 문자열과 결코 일치하지 않기 때문에 아마 해를 끼치 지 않을 것입니다.) –

0

데이터 파일을 다시 코딩 했습니까? 그렇지 않은 경우 UTF-8로 열면 작동하지 않습니다.

open $filehandle, '<:encoding(cp1252)', $filename or die ...; 

으로 열면 모든 항목 (tm)이 작동합니다.

코드를 다시 작성한 경우 무언가 잘못되어있는 것으로 보이며 그 내용을 분석하여 수정해야합니다. 실제로 파일에 무엇이 있는지 알아보기 위해 hexdump를 사용하는 것이 좋습니다. 텍스트 콘솔과 편집자가 거짓말을하는 경우가 있습니다.

+0

Hexdump는 1252자를 예상 한 위치에 91,923,93을 표시합니다. 이 경우에 정규 표현식이/\ x91// \ x92 /와 일치하지 않는 이유는 나를 혼란스럽게합니다. 내 텍스트 편집기가 ANSI로 작성된 1252자를 가진 파일과 utf8이 아닌 파일을 새로 작성했다고보고했습니다. Perl utf8 IO 레이어가 모든 파일을 utf8로 만들 것을 예상했습니다. 레거시 8859 파일에서 1252 문자를 필터링하는 방법을 찾을 때까지 다시 코딩 할 수 없습니다. 새로운 utf8 파일이 모두 포함되어 있기 때문에 – Beeblbrox

2

Encoding::FixLatin은 귀하와 동일한 방식으로 데이터가 손상되는 것을 수정하기 위해 작성되었습니다.

1

fallbackEncode.pm의 지원을 사용할 수도 있습니다.

use Encode qw[decode]; 

my $octets = "\x91 Foo \xE2\x98\xBA \x92"; 
my $string = decode('UTF-8', $octets, sub { 
    my ($ordinal) = @_; 
    return decode('Windows-1252', pack 'C', $ordinal); 
}); 

printf "<%s>\n", 
    join ' ', map { sprintf 'U+%.4X', ord $_ } split //, $string; 

출력 :

<U+2018 U+0020 U+0046 U+006F U+006F U+0020 U+263A U+0020 U+2019>