rails incompatible character encodings: Windows-31J and UTF-8에러

Posted by negabaro kim on Friday, March 5, 2021 Tags: rails   2 minute read

DB데이터를 csv파일로 export하는 데일리 배치가 아래와 같은 에러를 뿌리며 동작이 되지 않았다.

에러명은 incompatible character encodings: Windows-31J and UTF-8


원인

é와 같은 linux,mac에서 읽을 수 없는 문자(Windows-31J)가 들어오면서 csv export시 에러가 발생했다.

이번 케이스는 필자가 관리하는 시스템의 사용자가 白鷗大学라는 한자를 입력했는데 한자가 Windows-31J 였던것이 원인이었다.

아래 코드로 간단히 에러 재현이 가능했다.

CSV.open(File.join('/var/tmp/test.csv'), 'w', encoding: 'Windows-31J') do |csv|
  csv << %w( d é f )
end
#error: Encoding::UndefinedConversionError: U+00E9 from UTF-8 to Windows-31J

대응

invalid, undef옵션을 이용해 처리할 수 없는 문자를 ?로 변경하도록 했다.

아래는 해당 코드이다.

CSV.open(TEMP_CSV_FILE_PATH,'w', force_quotes: true, encoding:Encoding::SJIS, invalid: :replace, undef: :replace) do |csv|
  csv << %w( d é f )
end

삽질한 부분

삽질1. CSV.generate에서는 invalid,undef옵션이 없음

CSV.generate를 사용했는데 여기서는 invalid,undef옵션사용이 불가능했다.(버전업해도)

삽질2. csv버전이 3.1.6미만일 경우 invalid,undef옵션 사용이 불가능

Gemfile을 gem 'csv', "~> 3.1.6"로 수정하고

bundle update csv해서 csv버전을 3.1.9로 올리니 사용할 수 있었다.

메모

메모1.

첫행을 아래와 같이 기술해서 해결한 사람도 있는듯

# coding: Windows-31J

필자의 경우 고객의 요구로 SJIS형태로 export해야되어서 채용하지 않음

메모2.

CSV.generate로 파일 오브젝트를 통째로 넘겨줘서 s3에 업로드 하는 방식이었는데 generate에 undef,invalid옵션이 없는 관계로 아래와 같이 변경

TEMP_CSV_FILE_PATH = '/tmp/temp_csv.csv'
CSV.open(TEMP_CSV_FILE_PATH,'w', force_quotes: true, encoding:Encoding::SJIS, invalid: :replace, undef: :replace) do |csv|
  ...
end

client = Aws::S3::Client.new(region: Settings.aws.region, credentials: Aws::ECSCredentials.new)
#client = Aws::S3::Client.new(region: Settings.aws.region)
...
client.put_object(bucket: Settings.aws.delivery_bucket, key: key, body: File.read(TEMP_CSV_FILE_PATH))

메모3.

CSV.open말고 csv block에 태우기전 문자열에다가 encoding옵션으로 undef,invalid를 추가할 수 있는 방법도 있다.

필자는 비효율적이라 생각해 이 방법은 사용하지 않음

Solution3,Solution4가 이 내용에 해당한다.

도움이 된 기사

Shift_JIS와 Windows-31J 차이

Solution1

Solution2