adodb: กับดักข้อมูล

ต้องการพอร์ตข้อมูลที่เป็น dbf ของ Visual Foxpro มาลงใน postgres โดยใช้โมดูล adodb
ค้นกูเกิลเจอโมดูลในการอ่าน Visual Foxpro dbf ที่
เว็บของคุณ Yusdi Santoso หมวด Software Repository

ใช้งานได้ดีทีเดียว เพราะอ่าน Memo Field ของ Visual Foxpro ออกหมด

แต่ดันพลาดตอนไม่ได้ตรวจสอบข้อมูลของ Memo Field เพราะเขาเอาไบต์ที่เป็น Null มาด้วย ('\x00')
INSERT เข้าไปเท่าไหร่ก็แสดงข้อผิดพลาดอยู่ตลอด เสียเวลาทั้งวันในการดีบัก เพราะดันไปเพ่งเล็งที่ adodb กับ pyscopg
ข้อผิดพลาดที่แสดงคือ

 psycopg.ProgrammingError: ERROR:  unterminated quoted string at or near "'" at character XXX

ลองไปลองมาถึงได้ทราบว่าเป็นที่ Null character

แก้ด้วยการเติมฟังก์ชั่นการกรองข้อมูลคือ

def dncode(s):
  return s.strip().strip('\x00').decode('tis620').encode('utf8')

ให้ถอดรหัสอักขระด้วย tis620 ด้วย เพราะข้อมูลเก่าเป็นรหัสภาษาไทยแบบวินโดวส์

ผ่านเรียบร้อย โดยเสีย(ค่าฉลาดน้อย)ไปหนึ่งวัน

adodb: กับดักข้อมูล ๑

จากการทดลองนำเข้าข้อมูล dbf ในครั้งก่อน พบข้อผิดพลาดในการแปลงอีกอันนึง คือ สระอำ
หลังจากแปลงมาแล้ว พบว่าส่วนใหญ่จะแปลงได้ถูกต้อง ยกเว้นบางคำที่เขาแปลงออกมาเป็น 2 อักขระ
คือประกอบด้วย นิคหิต ( _ํ ) กับสระอา ( า ) แทนที่จะเป็นสระอำอักขระเดียว
ซึ่งยังไม่ทราบว่าเกิดจากสาเหตุอะไร (อาจเป็นข้อมูลต้นทางไม่ดีก็เป็นได้)

เราจึงควรตรวจสอบข้อมูล ในการนำเข้า ด้วยการกรองสระอำอีกชั้นนึงดังนี้

...
def dncode(s):
  return s.strip().strip('\x00').decode('tis620').encode('utf8').replace('\xe0\xb9\x8d\xe0\xb8\xb2','\xe0\xb8\xb3')
...

update
ถึงเวลาใช้งานจริงก็ยังมีข้อมูลที่ไม่อยู่ในช่วงของ Ascii Codepage-874 หลุดออกมา ทำให้การถอดรหัส (decode('tis620')) ยังรายงานข้อผิดพลาด
เราต้องถอดเอาอักขระขยะออกให้หมด
ฟังก์ชั่น dncode สุดท้ายจึงเป็นดังนี้

...
def dncode(s):
  return s.strip().strip('\x00').strip('\xa0').strip('\xdb').strip('\xdc').strip('\xdd').strip('\xde').strip('\xfc').strip('\xfd').strip('\xfe').strip('\xff').decode('tis620').encode('utf8').replace('\xe0\xb9\x8d\xe0\xb8\xb2','\xe0\xb8\xb3')
...

ตอนทำงาน ไพธอนจะทำงานจากซ้ายไปขวา จึงต้อง strip อักขระขยะออกก่อน แล้วจึงตามด้วยการ decode/encode เป็นลำดับสุดท้าย

Topic: