ToolDeck

CSV เป็น JSON ใน JavaScript

·Front-end & Node.js Developer·ตรวจสอบโดยSophie Laurent·เผยแพร่เมื่อ

ใช้ แปลง CSV เป็น JSON ฟรีโดยตรงในเบราว์เซอร์ของคุณ — ไม่ต้องติดตั้ง

ลอง แปลง CSV เป็น JSON ออนไลน์ →

ข้อมูล CSV ส่วนใหญ่ที่พบมักมาในรูปสตริงแบน จากการอัปโหลดไฟล์ การส่งออกจากฐานข้อมูล หรือ API ที่ยังใช้รูปแบบจากยุค 1970 เพื่อ แปลง CSV เป็น JSON ใน JavaScript คุณต้องการสองสิ่งที่ภาษาให้มาฟรี: การแบ่งสตริงเพื่อ parse แถว และ JSON.stringify() เพื่อ serialize ผลลัพธ์ ไม่จำเป็นต้องติดตั้ง npm สำหรับพื้นฐาน — คู่มือนี้ครอบคลุมทั้ง pipeline ตั้งแต่ยูทิลิตี csvToJson() ที่นำกลับมาใช้ได้ ไปจนถึง PapaParse และการทำงานกับไฟล์ใน Node.js สำหรับการแปลงด่วนโดยไม่ต้องเขียนโค้ด เครื่องมือแปลง CSV เป็น JSON ออนไลน์ ทำให้เสร็จทันที ตัวอย่างทั้งหมดรองรับ Node.js 18+ และเบราว์เซอร์สมัยใหม่

  • แบ่ง CSV ด้วยขึ้นบรรทัดใหม่ ดึง header จากแถว 0 map แถวที่เหลือเป็นอ็อบเจกต์ จากนั้นใช้ JSON.stringify(array, null, 2) สำหรับผลลัพธ์ที่อ่านง่าย
  • JSON.stringify() สร้างสตริง JSON.parse() แปลงกลับเป็นอาร์เรย์ JavaScript ที่มีชีวิต — รู้ว่าคุณมีอะไรก่อนดำเนินการ
  • อินสแตนซ์ Map ไม่ serialize เป็น JSON โดยอัตโนมัติ — เรียก Object.fromEntries(map) ก่อน
  • สำหรับ CSV ที่มี field มีเครื่องหมายคำพูด คอมม่าภายในค่า หรือขึ้นบรรทัดใหม่ในเซลล์ ใช้ PapaParse หรือ csv-parse แทนการแบ่งแบบง่าย
  • csvtojson (npm) จัดการการ coerce ชนิดข้อมูล สตรีมมิง และ edge case ของ RFC 4180 ในการเรียกครั้งเดียว

การแปลง CSV เป็น JSON คืออะไร?

การแปลง CSV เป็น JSON แปลงรูปแบบข้อความที่คั่นด้วยคอมม่าแบบแบนให้เป็นอาร์เรย์ของอ็อบเจกต์ ที่มีโครงสร้าง ซึ่งแต่ละแถวจะกลายเป็นอ็อบเจกต์ JavaScript ที่ใช้ header ของคอลัมน์เป็นคีย์ รูปแบบ CSV ไม่มีชนิดข้อมูล — ทุกอย่างเป็นสตริง JSON เพิ่มโครงสร้าง การซ้อนกัน และชนิดข้อมูลที่ชัดเจน (ตัวเลข บูลีน null) การแปลงนี้เป็นขั้นตอนแรกใน pipeline ข้อมูลเกือบทุกรายการที่เริ่มต้นจากการส่งออกสเปรดชีต การ dump จากระบบเก่า หรือ ไฟล์ที่ผู้ใช้อัปโหลด ข้อมูลพื้นฐานเหมือนเดิม รูปแบบเปลี่ยนจากคอลัมน์ที่ใช้ตำแหน่ง เป็น property ที่มีชื่อ

Before · json
After · json
name,email,role,active
สมชาย ใจดี,somchai@nexuslabs.io,Engineering Lead,true
นภา วงศ์สุข,napa@nexuslabs.io,Product Manager,true
[
  {
    "name": "สมชาย ใจดี",
    "email": "somchai@nexuslabs.io",
    "role": "Engineering Lead",
    "active": "true"
  },
  {
    "name": "นภา วงศ์สุข",
    "email": "napa@nexuslabs.io",
    "role": "Product Manager",
    "active": "true"
  }
]

csvToJson() — สร้างฟังก์ชันแปลงที่นำกลับมาใช้ได้

pipeline การแปลง CSV เป็น JSON ใน JavaScript แบ่งออกเป็นสามขั้นตอน: แบ่งสตริง CSV ด้วยขึ้นบรรทัดใหม่เพื่อรับแถว ดึง header จากแถวแรกด้วย split(','), จากนั้น map แต่ละแถวที่เหลือเป็นอ็อบเจกต์ JavaScript ธรรมดาที่มี key จาก header และ value จากตำแหน่งคอลัมน์ที่ตรงกัน การเรียก JSON.stringify() สุดท้ายแปลงอาร์เรย์ของอ็อบเจกต์นั้นเป็นสตริง JSON นี่คือเวอร์ชันที่ทำงานได้น้อยที่สุด:

JavaScript — minimal csvToJson
function csvToJson(csv) {
  const lines = csv.trim().split('\n')
  const headers = lines[0].split(',').map(h => h.trim())

  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(
        headers.map((header, i) => [header, values[i]?.trim()])
      )
    })

  return JSON.stringify(rows, null, 2)
}

const csv = `server,port,region,status
api-gateway,8080,us-east-1,healthy
auth-service,8443,eu-west-1,degraded
payments-api,9090,ap-south-1,healthy`

console.log(csvToJson(csv))
// [
//   { "server": "api-gateway", "port": "8080", "region": "us-east-1", "status": "healthy" },
//   { "server": "auth-service", "port": "8443", "region": "eu-west-1", "status": "degraded" },
//   { "server": "payments-api", "port": "9090", "region": "ap-south-1", "status": "healthy" }
// ]

ฟังก์ชันนั้นจัดการพื้นฐาน: ขึ้นบรรทัดใหม่ท้ายสตริง บรรทัดว่าง ช่องว่างรอบค่า ทุก field ของ CSV จะผ่านมาเป็นสตริง สังเกตว่า port คือ "8080" (สตริง) ไม่ใช่ 8080 (ตัวเลข) หากต้องการชนิดข้อมูลที่ถูกต้องในผลลัพธ์ JSON คุณต้อง coerce เอง นี่คือเวอร์ชันขยายพร้อมการตรวจจับชนิดข้อมูล:

JavaScript — csvToJson with type coercion
function coerceValue(val) {
  if (val === undefined || val === '') return null
  if (val === 'true') return true
  if (val === 'false') return false
  if (val === 'null') return null
  const num = Number(val)
  if (!isNaN(num) && val.trim() !== '') return num
  return val
}

function csvToJson(csv, { coerce = false } = {}) {
  const lines = csv.trim().split('\n')
  const headers = lines[0].split(',').map(h => h.trim())

  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(
        headers.map((header, i) => [
          header,
          coerce ? coerceValue(values[i]?.trim()) : values[i]?.trim()
        ])
      )
    })

  return JSON.stringify(rows, null, 2)
}

const csv = `endpoint,port,max_connections,debug
/api/v2/orders,8443,500,true
/api/v2/health,8080,100,false`

console.log(csvToJson(csv, { coerce: true }))
// [
//   { "endpoint": "/api/v2/orders", "port": 8443, "max_connections": 500, "debug": true },
//   { "endpoint": "/api/v2/health", "port": 8080, "max_connections": 100, "debug": false }
// ]

flag coerce เป็นแบบ opt-in เพราะการตรวจจับชนิดข้อมูลอัตโนมัติอาจให้ผลไม่ดี — field เช่นรหัสไปรษณีย์ ("07302") จะสูญเสียเลขศูนย์นำหน้าเมื่อแปลงเป็นตัวเลข เปิดใช้ coercion เฉพาะเมื่อคุณควบคุม schema หมายเหตุเพิ่มเติม: JSON.stringify() รับอาร์กิวเมนต์ที่สาม space สำหรับการย่อหน้า ส่ง 2 สำหรับสองช่อง 4 สำหรับสี่ช่อง หรือ "\t" สำหรับ tab ละเว้นเพื่อผลลัพธ์แบบกระชับในบรรทัดเดียว — มีประโยชน์เมื่อส่ง สตริง JSON เป็น body ของ API request ที่ช่องว่างเป็นแค่ bandwidth ที่เสียเปล่า

หมายเหตุ:สตริง CSV ดิบไม่ใช่ JSON การเรียก JSON.parse() โดยตรงบนข้อความ CSV จะเกิด SyntaxError คุณต้องแปลง CSV เป็นอ็อบเจกต์ JavaScript ก่อน ด้วยฟังก์ชัน csvToJson() ซึ่งภายในเรียก JSON.stringify() เพื่อสร้างสตริง JSON จริงๆ

การจัดการ Map, Date และอ็อบเจกต์กำหนดเองจากข้อมูล CSV

การแปลง CSV ไม่ได้จบลงเสมอด้วยอาร์เรย์แบนของอ็อบเจกต์ธรรมดา บางครั้งคุณต้องสร้าง Map จากคู่ header-value parse สตริงวันที่เป็นอ็อบเจกต์ Date หรือเพิ่ม property ที่คำนวณ ก่อน serialize JavaScript มีข้อที่ทำให้สับสน: อินสแตนซ์ Map ไม่ serialize ด้วย JSON.stringify()คุณจะได้อ็อบเจกต์ว่าง วิธีแก้คือ Object.fromEntries() เพื่อแปลง Map กลับเป็นอ็อบเจกต์ธรรมดาก่อน stringify

สาเหตุที่ Map serialize เป็น {} คือ JSON.stringify() วนซ้ำ property ของอ็อบเจกต์ที่ enumerable ได้ Map เก็บ entry ไว้ใน internal slot ไม่ใช่เป็น property ที่ enumerable บนอ็อบเจกต์เอง ดังนั้น serializer จึงเห็นอ็อบเจกต์ที่ไม่มี key prototype ของ Map ยังขาดเมธอด toJSON() ซึ่งเป็น hook ที่ JSON.stringify() เรียกก่อนสำหรับค่าใดๆ ก่อนตัดสินใจว่าจะ serialize อย่างไร หากค่ามี toJSON(), ค่าที่คืนจากเมธอดนั้นจะถูก serialize — ไม่ใช่อ็อบเจกต์เอง นี่คือเหตุที่อ็อบเจกต์ Date serialize ได้ถูกต้อง: Date.prototype.toJSON คืนสตริง ISO 8601 ดังนั้น JSON.stringify(new Date()) สร้าง timestamp ที่มีเครื่องหมายคำพูดแทนอ็อบเจกต์ว่าง การเข้าใจ hook นี้ให้คุณกำหนดพฤติกรรมเดียวกัน บนคลาสของคุณเอง — ดังที่แสดงในตัวอย่าง EmployeeRecord ด้านล่าง — เพื่อควบคุมว่า field ที่ได้จาก CSV ใดจะปรากฏในผลลัพธ์ JSON สุดท้าย

แปลง Map เป็น JSON

JavaScript — Map to JSON via Object.fromEntries()
// สร้าง Map จากคู่ header→value ของ CSV
const headers = ['server', 'port', 'region']
const values = ['payments-api', '9090', 'ap-south-1']
const rowMap = new Map(headers.map((h, i) => [h, values[i]]))

// Map ไม่ serialize โดยตรง
console.log(JSON.stringify(rowMap))
// "{}"  — อ็อบเจกต์ว่าง ข้อมูลหาย!

// แปลงเป็นอ็อบเจกต์ธรรมดาก่อน
const rowObj = Object.fromEntries(rowMap)
console.log(JSON.stringify(rowObj, null, 2))
// {
//   "server": "payments-api",
//   "port": "9090",
//   "region": "ap-south-1"
// }

สตริงวันที่และ toJSON()

field วันที่ใน CSV มาเป็นสตริง หากคุณ parse เป็นอ็อบเจกต์ Date ระหว่างการประมวลผล Date เหล่านั้นจะ serialize ถูกต้องเพราะ Date มีเมธอด toJSON() ที่ built-in ซึ่งคืนสตริง ISO 8601 คุณยังสามารถกำหนด toJSON() เองบนคลาสของคุณเพื่อควบคุมว่าคอลัมน์ CSV ใดจะปรากฏในผลลัพธ์ที่ serialize — ตัวอย่างเช่น การละ field ติดตามภายในเช่น _rowIndex

JavaScript — toJSON() for custom serialization
class EmployeeRecord {
  constructor(csvRow) {
    this._rowIndex = csvRow._rowIndex  // ภายใน ไม่ใช่สำหรับ JSON
    this.employeeId = csvRow.employee_id
    this.name = csvRow.name
    this.hiredAt = new Date(csvRow.hired_date)
    this.salary = Number(csvRow.salary)
  }

  toJSON() {
    // แสดงเฉพาะ field ที่ต้องการในผลลัพธ์ JSON
    return {
      employee_id: this.employeeId,
      name: this.name,
      hired_at: this.hiredAt,  // Date.toJSON() → ISO string อัตโนมัติ
      salary: this.salary,
    }
  }
}

const csvRow = {
  _rowIndex: 42,
  employee_id: 'EMP-2847',
  name: 'สมชาย ใจดี',
  hired_date: '2024-03-15',
  salary: '128000',
}

const record = new EmployeeRecord(csvRow)
console.log(JSON.stringify(record, null, 2))
// {
//   "employee_id": "EMP-2847",
//   "name": "สมชาย ใจดี",
//   "hired_at": "2024-03-15T00:00:00.000Z",
//   "salary": 128000
// }
// หมายเหตุ: _rowIndex ถูกยกเว้น salary เป็นตัวเลข วันที่อยู่ในรูปแบบ ISO

Reviver สำหรับการ Deserialize วันที่

หลังจากเขียน JSON ที่ได้จาก CSV ลงไฟล์หรือส่งผ่านเครือข่าย JSON.parse() จะคืนอ็อบเจกต์ธรรมดา — อ็อบเจกต์ Date จะกลายเป็นสตริงอีกครั้ง ใช้ฟังก์ชัน reviver เพื่อแปลงสตริง ISO 8601 กลับเป็นอ็อบเจกต์ Date ระหว่างการ parse:

JavaScript — reviver to reconstruct Date objects
const jsonString = '{"employee_id":"EMP-2847","name":"สมชาย ใจดี","hired_at":"2024-03-15T00:00:00.000Z","salary":128000}'

const isoDatePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/

const parsed = JSON.parse(jsonString, (key, value) => {
  if (typeof value === 'string' && isoDatePattern.test(value)) {
    return new Date(value)
  }
  return value
})

console.log(parsed.hired_at instanceof Date)  // true
console.log(parsed.hired_at.getFullYear())    // 2024
คำเตือน:JSON.stringify() คืน undefined (ไม่ใช่สตริง) สำหรับค่าที่มี function, Symbol หรือ property ที่เป็น undefined หากอ็อบเจกต์ที่ได้จาก CSV บังเอิญรับค่า undefined จากคอลัมน์ที่หายไป property นั้น จะหายออกจากผลลัพธ์ JSON โดยไม่มีการเตือน ควร default ค่าที่หายไปเป็น null เสมอ

เอกสารอ้างอิงพารามิเตอร์ JSON.stringify()

รูปแบบฟังก์ชันคือ JSON.stringify(value, replacer?, space?)อาร์กิวเมนต์ replacer และ space เป็น optional ทั้งคู่ — ส่ง null สำหรับ replacer เมื่อต้องการเฉพาะการย่อหน้า

พารามิเตอร์
ชนิดข้อมูล
ค่าเริ่มต้น
คำอธิบาย
value
any
(จำเป็น)
ค่า JavaScript ที่ต้องการ serialize — อ็อบเจกต์ อาร์เรย์ สตริง ตัวเลข บูลีน หรือ null
replacer
Function | Array | null
undefined
กรองหรือแปลงค่าระหว่างการ serialize อาร์เรย์ระบุชื่อ property ที่ต้องการเก็บ ฟังก์ชันรับคู่ (key, value)
space
number | string
undefined
การย่อหน้า: ตัวเลข 0–10 สำหรับช่องว่าง หรือสตริง (เช่น "\t") สำหรับการย่อหน้าแบบกำหนดเอง ละเว้นเพื่อแสดงผลแบบกระชับในบรรทัดเดียว

พารามิเตอร์ของ JSON.parse():

พารามิเตอร์
ชนิดข้อมูล
ค่าเริ่มต้น
คำอธิบาย
text
string
(จำเป็น)
สตริง JSON ที่ต้องการ parse — ต้องเป็น JSON ที่ถูกต้อง มิฉะนั้นจะเกิด SyntaxError
reviver
Function | undefined
undefined
เรียกสำหรับทุกคู่ key-value ค่าที่คืนกลับจะแทนที่ค่าเดิม คืน undefined เพื่อลบ property นั้น

JSON.parse() — การนำผลลัพธ์ JSON ไปใช้

เมื่อได้สตริง JSON จาก csvToJson(), ขั้นตอนถัดไปมักเป็นการ parse กลับเป็นอาร์เรย์ JavaScript ที่มีชีวิตสำหรับการกรอง การ mapping หรือการส่งไปยัง API ความแตกต่างระหว่างสตริง JSON (typeof === "string") และอ็อบเจกต์ JavaScript มีความสำคัญ คุณไม่สามารถเรียก .filter() หรือเข้าถึง [0].name บนสตริง — คุณต้องใช้ JSON.parse() ก่อน การทำงานแบบวงจร (stringify แล้ว parse) ยังทำงานเป็นเทคนิคตรวจสอบได้: หากการแปลง CSV สร้างสิ่งที่ไม่ใช่ JSON ที่ถูกต้อง parse จะ throw อาร์กิวเมนต์ optional ที่เรียกว่า reviver ให้คุณแปลงแต่ละคู่ key-value ระหว่างการ parse — มีประโยชน์ สำหรับการคืนอ็อบเจกต์ Date จากสตริง ISO หรือการเปลี่ยนชื่อ key โดยไม่ต้องผ่านครั้งแยก

JavaScript — parse JSON output and query rows
const csv = `endpoint,method,avg_latency_ms,error_rate
/api/v2/orders,POST,342,0.02
/api/v2/health,GET,12,0.00
/api/v2/payments,POST,890,0.15
/api/v2/users,GET,45,0.01`

// ขั้นตอนที่ 1: แปลง CSV เป็นสตริง JSON
const jsonString = csvToJson(csv, { coerce: true })

// ขั้นตอนที่ 2: parse กลับเป็นอาร์เรย์ JavaScript
const endpoints = JSON.parse(jsonString)

// ตรวจสอบว่าเป็นอาร์เรย์
console.log(Array.isArray(endpoints))  // true

// กรอง endpoint ที่มี latency สูง
const slow = endpoints.filter(ep => ep.avg_latency_ms > 200)
console.log(slow.map(ep => ep.endpoint))
// ["/api/v2/orders", "/api/v2/payments"]

// Destructure แถวแรก
const [first, ...rest] = endpoints
console.log(first.endpoint)  // "/api/v2/orders"
console.log(rest.length)     // 3

wrapper ที่ปลอดภัยสำหรับ JSON.parse() มีประโยชน์เมื่อตรวจสอบผลลัพธ์การแปลงก่อนการประมวลผลต่อเนื่อง หากการแปลง CSV สร้าง JSON ที่ผิดรูปแบบด้วยเหตุใดก็ตาม (input ที่ถูกตัด ข้อผิดพลาดด้านการเข้ารหัส) วิธีนี้จะรับไว้โดยไม่ crash:

JavaScript — safe parse wrapper
function safeParse(jsonString) {
  try {
    return { data: JSON.parse(jsonString), error: null }
  } catch (err) {
    return { data: null, error: err.message }
  }
}

// ผลลัพธ์ที่ถูกต้อง
const result = safeParse(csvToJson(csv))
if (result.error) {
  console.error('การแปลง CSV สร้าง JSON ที่ไม่ถูกต้อง:', result.error)
} else {
  console.log(`Parse แล้ว ${result.data.length} แถว`)
}

// ส่ง CSV ดิบไปยัง JSON.parse โดยไม่ได้ตั้งใจ — นี่จะล้มเหลว
const bad = safeParse('name,email\nสมชาย,somchai@nexuslabs.io')
console.log(bad.error)  // "Unexpected token 'a', "name,email"... is not valid JSON"

Reviver สำหรับการเปลี่ยนชื่อ Key และการตรวจสอบ

ฟังก์ชัน reviver รับทุกคู่ key-value ระหว่างการ parse จาก property ที่อยู่ในสุดออกมา การคืน undefined สำหรับ key จะลบมันออกจากผลลัพธ์ทั้งหมด การคืนค่าที่ต่างออกไปจะแทนที่มัน reviver มีประโยชน์สำหรับการเปลี่ยนชื่อ header (camelCase เป็น snake_case) การลบ field ภายใน หรือการตรวจสอบว่าคอลัมน์ที่จำเป็นมีอยู่ มันถูกเรียกด้วยค่า root สุดท้าย (key สตริงว่าง) ซึ่งเป็นที่ที่คุณ throw หากผลลัพธ์ไม่ใช่อาร์เรย์

JavaScript — reviver for key renaming and shape validation
const jsonString = csvToJson(`employeeId,firstName,hiredDate
EMP-2847,สมชาย,2024-03-15
EMP-3012,นภา,2023-11-01`, { coerce: false })

const camelToSnake = str => str.replace(/[A-Z]/g, c => '_' + c.toLowerCase())

const employees = JSON.parse(jsonString, function(key, value) {
  // ค่า root — ตรวจสอบรูปทรง
  if (key === '') {
    if (!Array.isArray(value)) throw new Error('Expected JSON array from CSV')
    return value
  }
  // เปลี่ยนชื่อ key camelCase เป็น snake_case
  if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
    return Object.fromEntries(
      Object.entries(value).map(([k, v]) => [camelToSnake(k), v])
    )
  }
  return value
})

console.log(employees[0])
// { employee_id: 'EMP-2847', first_name: 'สมชาย', hired_date: '2024-03-15' }

แปลง CSV จากไฟล์และ API Response

สองแหล่งที่ข้อมูล CSV มาจริงใน production: ไฟล์บนดิสก์และ HTTP response ทั้งสองสถานการณ์ต้องการการจัดการข้อผิดพลาดเพราะ input มาจากภายนอกและไม่สามารถควบคุมได้

อ่านไฟล์ CSV แปลง และเขียน JSON

Node.js 18+ — file conversion
import { readFileSync, writeFileSync } from 'node:fs'

function csvToJsonFromFile(inputPath, outputPath) {
  let csvText
  try {
    csvText = readFileSync(inputPath, 'utf8')
  } catch (err) {
    throw new Error(`ไม่สามารถอ่าน ${inputPath}: ${err.message}`)
  }

  const lines = csvText.trim().split('\n')
  if (lines.length < 2) {
    throw new Error(`${inputPath} ไม่มีแถวข้อมูล (มีเพียง ${lines.length} บรรทัด)`)
  }

  const headers = lines[0].split(',').map(h => h.trim())
  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(headers.map((h, i) => [h, values[i]?.trim()]))
    })

  const jsonOutput = JSON.stringify(rows, null, 2)
  writeFileSync(outputPath, jsonOutput, 'utf8')
  console.log(`แปลงแล้ว ${rows.length} แถว → ${outputPath}`)
  return rows
}

// การใช้งาน
const data = csvToJsonFromFile('inventory.csv', 'inventory.json')
console.log(data[0])
// { sku: "WDG-2847", warehouse: "us-east-1", quantity: "150", ... }

ดึง CSV จาก API Endpoint

Node.js 18+ — API response conversion
async function fetchCsvAsJson(url) {
  const response = await fetch(url)
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`)
  }

  const contentType = response.headers.get('content-type') || ''
  if (!contentType.includes('text/csv') && !contentType.includes('text/plain')) {
    console.warn(`content-type ไม่คาดคิด: ${contentType}`)
  }

  const csvText = await response.text()
  const lines = csvText.trim().split('\n')
  const headers = lines[0].split(',').map(h => h.trim())
  const rows = lines.slice(1)
    .filter(line => line.trim() !== '')
    .map(line => {
      const values = line.split(',')
      return Object.fromEntries(headers.map((h, i) => [h, values[i]?.trim()]))
    })

  return rows
}

// ตัวอย่าง: ดึง CSV อัตราแลกเปลี่ยนจากผู้ให้บริการข้อมูล
try {
  const rates = await fetchCsvAsJson('https://data.ecb.internal/rates/daily.csv')
  console.log(JSON.stringify(rates.slice(0, 3), null, 2))
  // ส่งเป็น JSON ไปยัง service ต่อเนื่อง
  await fetch('https://api.internal/v2/rates', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ data: rates }),
  })
} catch (err) {
  console.error('การซิงค์อัตราแลกเปลี่ยนล้มเหลว:', err.message)
}
หมายเหตุ:อาร์กิวเมนต์ replacer ใน JSON.stringify() ให้คุณ whitelist คอลัมน์เฉพาะ จาก CSV ส่งอาร์เรย์ชื่อ header เพื่อรวมเฉพาะ field เหล่านั้น: JSON.stringify(rows, ['name', 'email', 'department'])Property ที่ไม่อยู่ในอาร์เรย์จะถูกยกเว้นออกจากผลลัพธ์โดยไม่มีการเตือน

การแปลง CSV เป็น JSON ผ่าน Command Line

Node.js สามารถรัน inline script ได้ และมีเครื่องมือ CLI เฉพาะที่จัดการการแปลง CSV เป็น JSON โดยไม่ต้องเขียน script

bash — Node.js one-liner
# Pipe CSV ไปยัง inline script ของ Node.js
cat servers.csv | node -e "
  const lines = require('fs').readFileSync('/dev/stdin','utf8').trim().split('\n');
  const h = lines[0].split(',');
  const rows = lines.slice(1).map(l => Object.fromEntries(h.map((k,i) => [k.trim(), l.split(',')[i]?.trim()])));
  console.log(JSON.stringify(rows, null, 2));
"
bash — Miller (mlr) for CSV to JSON
# Miller เป็น Swiss Army knife สำหรับข้อมูลที่มีโครงสร้าง
# ติดตั้ง: brew install miller (macOS) หรือ apt install miller (Debian/Ubuntu)
mlr --icsv --ojson cat inventory.csv

# กรองแถวระหว่างการแปลง
mlr --icsv --ojson filter '$quantity > 100' inventory.csv

# เลือกคอลัมน์เฉพาะ
mlr --icsv --ojson cut -f sku,warehouse,quantity inventory.csv
bash — csvtojson CLI
# ติดตั้งแบบ global
npm install -g csvtojson

# แปลงไฟล์
csvtojson servers.csv > servers.json

# Pipe จาก stdin
cat exports/q1-metrics.csv | csvtojson > q1-metrics.json

สำหรับไฟล์ขนาดใหญ่ Miller มักเป็นตัวเลือกที่ดีกว่า csvtojson Miller ถูกเขียนด้วย C และประมวลผล CSV เป็น stream โดยไม่โหลดไฟล์ทั้งหมดเข้าหน่วยความจำ ซึ่งหมายความว่าสามารถจัดการกับ export ขนาดหลาย GB ด้วยการใช้หน่วยความจำคงที่ มันยังรองรับการดำเนินการระดับ field ในที่เดียว — การเปลี่ยนชื่อคอลัมน์ การแปลงชนิดข้อมูล การกรองแถว — ก่อนที่ข้อมูลจะกลายเป็น JSON ดังนั้นคุณจึงหลีกเลี่ยง pipeline แบบสองขั้นตอน parse-then-transform ในทางกลับกัน csvtojson ทำงานบน Node.js และสะดวกกว่าเมื่อ toolchain ที่เหลือเป็น JavaScript: คุณสามารถ pipe output ไปยัง Node streams โดยตรง import เป็น library หรือใช้ API colParser สำหรับการ coerce ชนิดข้อมูลต่อคอลัมน์ในโค้ด ใช้ Miller สำหรับ throughput สูงและ shell pipeline ใช้ csvtojson เมื่อต้องการการผสานรวมกับแอปพลิเคชัน Node.js อย่างใกล้ชิด

หมายเหตุ:jq ไม่ parse CSV โดยตรง หากต้องการใช้ jq ใน pipeline ให้แปลงเป็น JSON ก่อนด้วย csvtojson หรือ mlr จากนั้น pipe ผลลัพธ์ JSON ไปยัง jq สำหรับการกรองและแปลง

ทางเลือกที่มีประสิทธิภาพสูง — PapaParse

วิธีการ split(',') แบบง่ายจะพังกับไฟล์ CSV จากโลกความเป็นจริง field ที่มีเครื่องหมายคำพูดซึ่งมีคอมม่า ขึ้นบรรทัดใหม่ที่ฝังอยู่ เครื่องหมายคำพูดคู่ที่ escape — ทั้งหมดนี้ทำให้การแบ่งแบบง่ายพัง PapaParse คือ library ที่เหมาะสำหรับเมื่อ CSV มาจากแหล่งที่ไม่รู้จัก มันจัดการ edge case ทุกกรณีของ RFC 4180 ตรวจจับตัวคั่นอัตโนมัติ และทำงานได้ทั้งใน Node.js และเบราว์เซอร์

bash — install PapaParse
npm install papaparse
JavaScript — PapaParse with type coercion
import Papa from 'papaparse'

const csv = `product,description,price,in_stock
"Widget, Large","A premium widget with ""extra"" features",29.99,true
Bolt Assembly,Standard M8 bolt kit,4.50,true
"Gasket Set","Includes gasket, seal, and O-ring",12.75,false`

const { data, errors, meta } = Papa.parse(csv, {
  header: true,
  dynamicTyping: true,     // แปลงตัวเลขและบูลีนอัตโนมัติ
  skipEmptyLines: true,
  transformHeader: h => h.trim().toLowerCase().replace(/\s+/g, '_'),
})

if (errors.length > 0) {
  console.error('ข้อผิดพลาดในการ parse:', errors)
}

console.log(JSON.stringify(data, null, 2))
// [
//   {
//     "product": "Widget, Large",
//     "description": "A premium widget with \"extra\" features",
//     "price": 29.99,
//     "in_stock": true
//   },
//   ...
// ]
console.log(`Parse แล้ว ${data.length} แถว ตัวคั่น: "${meta.delimiter}"`)

ตัวเลือก dynamicTyping ของ PapaParse ทำการ coerce ชนิดข้อมูลอัตโนมัติ — ตัวเลขกลายเป็นตัวเลข "true"/"false" กลายเป็นบูลีน callback transformHeader ทำให้ชื่อคอลัมน์เป็น snake_case มาตรฐาน ซึ่งช่วยให้ไม่ต้องจัดการกับ header ที่ไม่สอดคล้องกัน จาก CSV export ที่ต่างกัน สำหรับการแปลงด่วนโดยไม่ต้องเขียนโค้ด parse ใดๆ เครื่องมือแปลง CSV เป็น JSON จัดการทั้งหมดนี้ในเบราว์เซอร์

Output ใน Terminal พร้อม Syntax Highlighting

การ dump อาร์เรย์ JSON ขนาดใหญ่ลงใน terminal ทำให้สายตาเบลอเร็ว การเพิ่ม syntax highlighting ให้กับ output ทำให้อ่านได้ง่ายขึ้นระหว่างการ debug และการพัฒนา แพ็กเกจ cli-highlight เพิ่มสีให้กับ JSON output ใน Node.js terminal

bash — install cli-highlight
npm install cli-highlight
JavaScript — colorized JSON output in terminal
import { highlight } from 'cli-highlight'

// หลังจากแปลง CSV เป็นอาร์เรย์ JSON
const jsonOutput = JSON.stringify(rows, null, 2)

// แสดงพร้อม syntax highlighting
console.log(highlight(jsonOutput, { language: 'json' }))
// Key สตริง ตัวเลข และบูลีนแต่ละอย่างได้รับสีที่แตกต่างกัน

Output ที่มีสีสันจะคุ้มค่าเมื่อคุณตรวจสอบผลลัพธ์การแปลงขนาดใหญ่แบบ interactive JSON key ค่าสตริง ตัวเลข และบูลีนแต่ละอย่างได้รับสี ANSI ที่แตกต่างกัน ซึ่งทำให้ง่ายต่อการสังเกตว่า field ใดมีชนิดข้อมูลผิด — ตัวอย่างเช่น หมายเลข port ที่ควรเป็น 8080 แต่ถูก highlight เป็นสตริงเพราะ coercion ปิดอยู่ สิ่งนี้มีประโยชน์เป็นพิเศษเมื่อ debug ไฟล์ CSV ที่ส่งออกจากเครื่องมือสเปรดชีตที่ชนิดข้อมูลของคอลัมน์ไม่สอดคล้องกัน ระหว่างแถว หากไม่มีสี การสแกน JSON 50 แถวเพื่อหา field ที่ผิดชนิดข้อมูลเดียว หมายถึงการอ่านทุกค่าทีละตัว เมื่อมีสี ตัวเลขที่ถูก highlight เป็นสตริงจะโดดเด่นทันที

คำเตือน:Syntax highlighting เพิ่ม ANSI escape code ให้กับ output อย่าใช้มัน เมื่อเขียน JSON ลงไฟล์ การ pipe ไปยังโปรแกรมอื่น หรือส่งเป็น body ของ API response — escape code จะทำให้ JSON เสียหาย ใช้ highlighting เฉพาะสำหรับการแสดงผลใน terminal

การทำงานกับไฟล์ CSV ขนาดใหญ่

การโหลดไฟล์ CSV ขนาด 500 MB เข้าสตริงด้วย readFileSync() จะกินหน่วยความจำและอาจทำให้ process crash สำหรับไฟล์ขนาดใหญ่ ควร stream CSV ทีละบรรทัดและ emit อ็อบเจกต์ JSON เมื่อมาถึง แพ็กเกจ csv-parse (ส่วนหนึ่งของ csv ecosystem บน npm) มี streaming parser ที่ทำงานกับ Node.js streams

Streaming CSV เป็น NDJSON ด้วย csv-parse

NDJSON (Newline-Delimited JSON) คือรูปแบบที่แต่ละบรรทัดของไฟล์ output เป็นอ็อบเจกต์ JSON ที่ครบสมบูรณ์ในตัวเอง แตกต่างจากอาร์เรย์ JSON ขนาดใหญ่เดียว — ซึ่งต้องการให้ไฟล์ทั้งหมด อยู่ในหน่วยความจำก่อนเริ่มอ่าน — ไฟล์ NDJSON สามารถประมวลผลทีละบรรทัดได้ ทำให้ NDJSON เหมาะสำหรับ dataset ขนาดใหญ่ที่จะถูกใช้โดย log processor stream pipeline หรือฐานข้อมูลที่มี API นำเข้าแบบ bulk แพ็กเกจ csv-parse emit อ็อบเจกต์ JavaScript หนึ่งอันต่อแถว CSV ใน object mode ดังนั้นคุณสามารถ pipe ไปยัง transform stream ที่ต่อท้าย \n หลังแต่ละ JSON.stringify(row)

Node.js 18+ — streaming CSV to NDJSON
import { createReadStream, createWriteStream } from 'node:fs'
import { parse } from 'csv-parse'
import { Transform } from 'node:stream'
import { pipeline } from 'node:stream/promises'

// แปลงแต่ละ CSV row object เป็น JSON line
const toNdjson = new Transform({
  objectMode: true,
  transform(record, encoding, callback) {
    callback(null, JSON.stringify(record) + '\n')
  },
})

await pipeline(
  createReadStream('telemetry-2026-03.csv'),
  parse({
    columns: true,       // ใช้แถวแรกเป็น header
    skip_empty_lines: true,
    trim: true,
    cast: true,          // แปลงตัวเลขและบูลีนอัตโนมัติ
  }),
  toNdjson,
  createWriteStream('telemetry-2026-03.ndjson')
)

console.log('การแปลงแบบ streaming เสร็จสมบูรณ์')
// แต่ละบรรทัดในไฟล์ output คืออ็อบเจกต์ JSON หนึ่งอัน:
// {"timestamp":"2026-03-15T08:22:00Z","service":"gateway","latency_ms":42,"status":200}
// {"timestamp":"2026-03-15T08:22:01Z","service":"auth","latency_ms":156,"status":401}
// ...

PapaParse Streaming สำหรับเบราว์เซอร์และ Node.js

โหมด streaming ของ PapaParse ใช้ callback step ที่ทำงานครั้งละหนึ่งแถวแทนที่จะเก็บแถวทั้งหมดในหน่วยความจำ คุณส่ง Node.js ReadStream (ใน Node.js) หรืออ็อบเจกต์ File (ในเบราว์เซอร์) และ PapaParse จัดการการแบ่งเป็น chunk ภายใน ไม่ต้องต่อ stream pipeline — แค่ callback ใช้เมื่อต้องการความสอดคล้องกับ RFC 4180 โดยไม่ต้องดึง csv-parse มาใช้

Node.js — PapaParse streaming large file
import Papa from 'papaparse'
import { createReadStream } from 'node:fs'

let rowCount = 0
const errors = []

const fileStream = createReadStream('warehouse-inventory.csv')

Papa.parse(fileStream, {
  header: true,
  dynamicTyping: true,
  step(result) {
    // ประมวลผลทีละแถว — หน่วยความจำคงที่
    rowCount++
    if (result.data.quantity === 0) {
      errors.push(`แถว ${rowCount}: ${result.data.sku} หมดสต็อก`)
    }
  },
  complete() {
    console.log(`ประมวลผลแล้ว ${rowCount} แถว`)
    if (errors.length > 0) {
      console.log(`พบปัญหา: ${errors.length}`)
      errors.forEach(e => console.log(`  ${e}`))
    }
  },
  error(err) {
    console.error('การ parse ล้มเหลว:', err.message)
  },
})
หมายเหตุ:เปลี่ยนไปใช้ streaming เมื่อไฟล์ CSV มีขนาดเกิน 50 MB หรือเมื่อประมวลผล input ที่ไม่มีขอบเขต (WebSocket feed, server-sent events, piped stdin) รูปแบบ NDJSON (อ็อบเจกต์ JSON หนึ่งอันต่อบรรทัด) มักเป็นรูปแบบ output ที่ดีกว่าอาร์เรย์ JSON ขนาดใหญ่ สำหรับ dataset ขนาดใหญ่ — สามารถประมวลผลทีละบรรทัดโดยไม่ต้องโหลดไฟล์ทั้งหมดเข้าหน่วยความจำ

ข้อผิดพลาดที่พบบ่อย

เรียก JSON.parse() โดยตรงบนสตริง CSV

ปัญหา: CSV ไม่ใช่ JSON การส่งสตริง CSV ดิบไปยัง JSON.parse() จะเกิด SyntaxError เพราะคอมม่าและขึ้นบรรทัดใหม่ไม่ใช่ไวยากรณ์ JSON ที่ถูกต้อง

วิธีแก้: Parse CSV เป็นอ็อบเจกต์ JavaScript ก่อนโดยใช้ split() หรือ library จากนั้นใช้ JSON.stringify() เพื่อสร้าง JSON เรียก JSON.parse() เฉพาะกับสตริงที่เป็น JSON ที่ถูกต้องแล้วเท่านั้น

Before · JavaScript
After · JavaScript
const csv = 'name,email\nสมชาย ใจดี,somchai@nexuslabs.io'
const data = JSON.parse(csv)
// SyntaxError: Unexpected token 'a'
const csv = 'name,email\nสมชาย ใจดี,somchai@nexuslabs.io'
const lines = csv.trim().split('\n')
const headers = lines[0].split(',')
const rows = lines.slice(1).map(line =>
  Object.fromEntries(headers.map((h, i) => [h, line.split(',')[i]]))
)
const json = JSON.stringify(rows, null, 2)  // สตริง JSON ที่ถูกต้อง
ใช้ toString() แทน JSON.stringify()

ปัญหา: การเรียก toString() บนอ็อบเจกต์ JavaScript คืนสตริงที่ไม่มีประโยชน์ '[object Object]' แทนที่จะเป็นข้อมูลจริง สิ่งนี้ทำลาย output การแปลง CSV เป็น JSON อย่างเงียบๆ

วิธีแก้: ใช้ JSON.stringify() เสมอเพื่อแปลงอ็อบเจกต์ JavaScript เป็นสตริง JSON toString() มีไว้สำหรับการ coerce primitive เป็นสตริง ไม่ใช่สำหรับ serialization

Before · JavaScript
After · JavaScript
const row = { server: 'api-gateway', port: 8080 }
const output = row.toString()
// "[object Object]"  — ข้อมูลหายไป
const row = { server: 'api-gateway', port: 8080 }
const output = JSON.stringify(row, null, 2)
// '{"server":"api-gateway","port":8080}'
แบ่งด้วยคอมม่าโดยไม่จัดการ field ที่มีเครื่องหมายคำพูด

ปัญหา: การ split(",") แบบง่ายพังเมื่อค่า CSV มีคอมม่าภายใน field ที่มีเครื่องหมายคำพูด: "Widget, Large" กลายเป็นสองค่าแยกกันแทนที่จะเป็นหนึ่ง

วิธีแก้: ใช้ PapaParse หรือ csv-parse สำหรับข้อมูล CSV ที่คุณไม่ได้ควบคุมทั้งหมด หากต้อง parse แบบ manual ให้เขียน state-machine parser ที่ติดตามว่าตำแหน่งปัจจุบันอยู่ใน field ที่มีเครื่องหมายคำพูดหรือไม่

Before · JavaScript
After · JavaScript
const line = '"Widget, Large","Premium quality",29.99'
const values = line.split(',')
// ["\"Widget", " Large\"", "\"Premium quality\"", "29.99"]
// 4 ค่าแทนที่จะเป็น 3 — field แรกถูกแบ่งผิด
import Papa from 'papaparse'
const { data } = Papa.parse('"Widget, Large","Premium quality",29.99')
// data[0] = ["Widget, Large", "Premium quality", "29.99"]
// 3 ค่า parse ถูกต้อง
ลืมว่าค่า CSV ทั้งหมดเป็นสตริง

ปัญหา: หากไม่ coerce ชนิดข้อมูล port: "8080" จะยังคงเป็นสตริงใน JSON แทนที่จะเป็นตัวเลข ระบบ downstream ที่คาดหวังชนิดข้อมูลตัวเลขจะปฏิเสธหรือจัดการข้อมูลผิดพลาด

วิธีแก้: ใช้การ coerce ชนิดข้อมูลแบบชัดเจนระหว่างขั้นตอนการ mapping หรือใช้ PapaParse พร้อม dynamicTyping: true ควรตั้งใจเสมอว่า field ใดควรเป็นตัวเลข

Before · JavaScript
After · JavaScript
const row = { port: '8443', debug: 'true', workers: '4' }
JSON.stringify(row)
// {"port":"8443","debug":"true","workers":"4"}  — ทุกอย่างเป็นสตริง
const row = {
  port: Number('8443'),           // 8443
  debug: 'true' === 'true',      // true
  workers: Number('4'),           // 4
}
JSON.stringify(row)
// {"port":8443,"debug":true,"workers":4}  — ชนิดข้อมูลถูกต้อง

การ Parse แบบ Manual กับ Library — เปรียบเทียบอย่างรวดเร็ว

วิธีการ
ผลลัพธ์สวยงาม
JSON ที่ถูกต้อง
ชนิดข้อมูลกำหนดเอง
สตรีมมิง
ต้องติดตั้งเพิ่ม
JSON.stringify()
✓ (ด้วย space)
✓ ผ่าน toJSON()/replacer
ไม่ (built-in)
JSON.parse()
ไม่มี (การ parse)
✓ (ตรวจสอบ)
✓ ผ่าน reviver
ไม่ (built-in)
csv-parse (Node.js)
✗ (คืนอ็อบเจกต์)
✗ (ไม่ใช่ JSON)
npm install
PapaParse
✗ (คืนอ็อบเจกต์)
✗ (ไม่ใช่ JSON)
npm install
csvtojson
✓ ผ่าน colParser
npm install
jq (CLI)
ไม่มี
ติดตั้งในระบบ
Miller (CLI)
ไม่มี
ติดตั้งในระบบ

สำหรับ script ขนาดเล็กที่คุณควบคุมรูปแบบ CSV และรู้ว่าไม่มี field ที่มีเครื่องหมายคำพูด วิธีการ split() + JSON.stringify() ที่ built-in ใช้งานได้และไม่ต้องพึ่งพา dependency ใดๆ สำหรับระบบ production ที่ประมวลผลไฟล์ CSV ที่ผู้ใช้อัปโหลด ใช้ PapaParse ในเบราว์เซอร์หรือ csv-parse ใน Node.js — ทั้งคู่จัดการ RFC 4180 ได้อย่างถูกต้องและรองรับ streaming แพ็กเกจ csvtojson เป็นตัวเดียวที่ output JSON โดยตรง จัดการทั้งการ parse และการ serialize ในการเรียกครั้งเดียว เมื่อต้องการเส้นทางที่เร็วที่สุดจากการวางถึงผลลัพธ์ เครื่องมือแปลง CSV เป็น JSON จัดการทั้งหมดในเบราว์เซอร์โดยไม่ต้องตั้งค่าใดๆ

คำถามที่พบบ่อย

วิธีแปลง CSV เป็น JSON ใน JavaScript โดยไม่ใช้ไลบรารี?

แบ่งสตริง CSV ด้วยขึ้นบรรทัดใหม่เพื่อรับแถว ดึง header จากแถวแรกด้วย split(",") จากนั้น map แถวที่เหลือเป็นอ็อบเจกต์โดยใช้ header เป็นคีย์ สุดท้ายใช้ JSON.stringify(array, null, 2) เพื่อสร้างสตริง JSON ที่อ่านง่าย วิธีนี้ใช้ได้ดีกับไฟล์ CSV เรียบง่ายที่คุณควบคุมรูปแบบและรู้ว่าไม่มี field ที่มีเครื่องหมายคำพูดหรือคอมม่าฝังอยู่ สำหรับข้อมูลที่ส่งออกจากสเปรดชีตหรือระบบภายนอก field ที่มีเครื่องหมายคำพูดและค่าหลายบรรทัดจะทำให้การแบ่งแบบง่ายพัง — ควรเปลี่ยนไปใช้ PapaParse หรือ csv-parse ในกรณีเหล่านั้น สำหรับไฟล์ขนาดเล็กที่ประมวลผลในเบราว์เซอร์ วิธีที่ไม่ต้องพึ่งพา dependency นี้เหมาะที่สุด

JavaScript
const csv = `name,email,department
สมชาย ใจดี,somchai@nexuslabs.io,Engineering
นภา วงศ์สุข,napa@nexuslabs.io,Product`

const lines = csv.trim().split('\n')
const headers = lines[0].split(',')
const rows = lines.slice(1).map(line => {
  const values = line.split(',')
  return Object.fromEntries(headers.map((h, i) => [h.trim(), values[i]?.trim()]))
})

console.log(JSON.stringify(rows, null, 2))
// [
//   { "name": "สมชาย ใจดี", "email": "somchai@nexuslabs.io", "department": "Engineering" },
//   { "name": "นภา วงศ์สุข", "email": "napa@nexuslabs.io", "department": "Product" }
// ]

ความแตกต่างระหว่าง JSON.stringify() และ toString() สำหรับอ็อบเจกต์คืออะไร?

toString() บนอ็อบเจกต์ธรรมดาจะคืนสตริงที่ไม่มีประโยชน์ "[object Object]" — ไม่บอกอะไรเกี่ยวกับข้อมูลจริง JSON.stringify() สร้างสตริง JSON ที่ถูกต้องพร้อม key และ value ทั้งหมดที่ serialize อย่างถูกต้อง รวมถึงอ็อบเจกต์และอาร์เรย์ที่ซ้อนกัน ใช้ JSON.stringify() เสมอเมื่อต้องการแปลงอ็อบเจกต์ JavaScript (เช่นแถวที่ได้จาก CSV) เป็นสตริง JSON ในการย้อนกลับการดำเนินการ — สร้างอ็อบเจกต์ JavaScript ที่มีชีวิตจากสตริง JSON — ใช้ JSON.parse() ซึ่งเป็นการดำเนินการผกผันของ JSON.stringify() ฟังก์ชันทั้งสองนี้สร้างวงจรสมบูรณ์: stringify เพื่อบันทึกหรือส่งข้อมูล parse เพื่อนำกลับมาใช้

JavaScript
const row = { name: 'สมชาย ใจดี', role: 'Engineer' }

console.log(row.toString())       // "[object Object]"
console.log(JSON.stringify(row))   // '{"name":"สมชาย ใจดี","role":"Engineer"}'

วิธีจัดการกับ field ใน CSV ที่มีคอมม่าหรือเครื่องหมายคำพูด?

RFC 4180 กำหนดว่า field ที่มีคอมม่า ขึ้นบรรทัดใหม่ หรือเครื่องหมายคำพูดคู่ต้องห่อด้วยเครื่องหมายคำพูดคู่ โดยเครื่องหมายคำพูดที่ฝังอยู่จะถูก escape ด้วยการซ้ำกัน ("" ภายใน field ที่มีเครื่องหมายคำพูดแทน quote เดี่ยวหนึ่งตัว) การใช้ split(",") แบบง่ายจะพังกับไฟล์เหล่านี้ — ขอบเขต field ไม่ใช่คอมม่าธรรมดาอีกต่อไป ใช้ PapaParse หรือ csv-parse สำหรับข้อมูลที่ใช้งานจริง หรือเขียน state-machine parser ที่ติดตามว่าอยู่ใน field ที่มีเครื่องหมายคำพูดหรือไม่ การเขียน state machine ที่ถูกต้องตั้งแต่ต้นนั้นซับซ้อนกว่าที่คิด: ต้องจัดการเครื่องหมายคำพูดที่จุดเริ่มต้นของ field เครื่องหมายคำพูด escape กลางคัน ขึ้นบรรทัดใหม่ภายใน field ที่มีเครื่องหมายคำพูด และรูปแบบ line ending ที่ต่างกัน (CRLF กับ LF) สำหรับข้อมูล CSV ที่ซับซ้อนกว่าระดับทดสอบ ควรใช้ไลบรารีที่ผ่านการทดสอบมาแล้ว

JavaScript
// PapaParse จัดการ RFC 4180 ได้อย่างถูกต้อง
import Papa from 'papaparse'

const csv = `product,description,price
"Widget, Large","A big ""widget""",29.99
Bolt,Standard bolt,1.50`

const { data } = Papa.parse(csv, { header: true })
console.log(JSON.stringify(data, null, 2))
// description field มีค่าที่ถูกต้อง: A big "widget"

แปลง CSV เป็น JSON โดยตรงในเบราว์เซอร์ได้ไหม?

ได้ ทั้ง JSON.stringify() และ JSON.parse() มีอยู่ใน engine ของเบราว์เซอร์ทุกตัว สำหรับขั้นตอนการ parse CSV คุณสามารถแบ่งด้วยขึ้นบรรทัดใหม่และคอมม่าสำหรับไฟล์เรียบง่าย หรือรวม PapaParse ผ่าน CDN (ไม่มี dependency สำหรับ Node.js) การแปลงทั้งหมดเกิดขึ้นฝั่ง client โดยไม่ต้องส่งข้อมูลไปเซิร์ฟเวอร์ ซึ่งมีประโยชน์สำหรับความเป็นส่วนตัวของไฟล์ — ข้อมูล CSV ดิบไม่เคยออกจากเครื่องของผู้ใช้ เมื่อผู้ใช้อัปโหลดไฟล์ CSV ผ่านองค์ประกอบ <input type="file"> เมธอด file.text() ของ File API คืน Promise ที่ resolve เป็นเนื้อหาของไฟล์เป็นสตริง ซึ่งสามารถส่งไปยังฟังก์ชันแปลงได้ ทำให้การแปลง CSV เป็น JSON ในเบราว์เซอร์อย่างสมบูรณ์เป็นไปได้จริงสำหรับ dashboard เครื่องมือสำหรับนักพัฒนา และแอปที่ต้องประมวลผลข้อมูลที่อัปโหลดโดยไม่ต้องมี backend

JavaScript
// เบราว์เซอร์: ผู้ใช้อัปโหลดไฟล์ CSV
const fileInput = document.querySelector('input[type="file"]')
fileInput.addEventListener('change', async (event) => {
  const file = event.target.files[0]
  const text = await file.text()
  const lines = text.trim().split('\n')
  const headers = lines[0].split(',')
  const rows = lines.slice(1).map(line =>
    Object.fromEntries(headers.map((h, i) => [h.trim(), line.split(',')[i]?.trim()]))
  )
  console.log(JSON.stringify(rows, null, 2))
})

วิธี parse ค่าตัวเลขและบูลีนจาก CSV แทนที่จะเก็บทุกอย่างเป็นสตริง?

CSV ไม่มีระบบชนิดข้อมูล — ทุก field เป็นสตริง คุณต้อง coerce ค่าระหว่างขั้นตอนการ mapping ตรวจสอบรูปแบบตัวเลขด้วย Number() หรือ parseFloat() แปลง "true"/"false" เป็นบูลีน และจัดการสตริงว่างเป็น null ระวัง field ที่ดูเหมือนตัวเลขแต่ต้องเป็นสตริง: รหัสไปรษณีย์เช่น "07302" จะสูญเสียเลขศูนย์นำหน้าเมื่อ coerce ด้วย Number() และหมายเลขโทรศัพท์หรือรหัสสินค้าที่มีตัวเลขก็มีปัญหาเดียวกัน ไลบรารี csvtojson ทำการ coerce ชนิดข้อมูลอัตโนมัติผ่านตัวเลือก colParser ซึ่งให้คุณระบุฟังก์ชันแปลงต่อคอลัมน์และแทนที่การตรวจจับอัตโนมัติสำหรับคอลัมน์ที่มีปัญหา ตัวเลือก dynamicTyping ของ PapaParse ใช้การ coerce เดียวกันกับทุกคอลัมน์

JavaScript
function coerceValue(val) {
  if (val === '') return null
  if (val === 'true') return true
  if (val === 'false') return false
  const num = Number(val)
  if (!isNaN(num) && val.trim() !== '') return num
  return val
}

// ใช้ระหว่างการ map จาก CSV เป็นอ็อบเจกต์
const row = { port: coerceValue('8443'), debug: coerceValue('true'), host: coerceValue('api.internal') }
// { port: 8443, debug: true, host: "api.internal" }

วิธีเขียนผลลัพธ์ CSV เป็น JSON ลงไฟล์ใน Node.js?

ใช้ fs.writeFileSync() พร้อมผลลัพธ์จาก JSON.stringify() อาร์กิวเมนต์ที่สามของ JSON.stringify ควบคุมการย่อหน้า — ส่ง 2 สำหรับการย่อหน้าสองช่อง หรือ "\t" สำหรับ tab เพื่ออ่านไฟล์กลับคืน ใช้ JSON.parse(fs.readFileSync(path, "utf8")) ซึ่งจะสร้างอาร์เรย์ JavaScript ของอ็อบเจกต์ขึ้นใหม่ หากเขียนไฟล์ในบริบท async (ภายใน async function หรือที่ระดับบนสุดของ ES module) ควรใช้ fs.promises.writeFile() เพื่อหลีกเลี่ยงการบล็อก event loop ขณะเขียนไฟล์ สำหรับผลลัพธ์ JSON ขนาดใหญ่หลายเมกะไบต์ ควรพิจารณาใช้ JSON stream ไปยัง WriteStream แทนการสร้างสตริงทั้งหมดในหน่วยความจำก่อนเขียน

JavaScript
import { writeFileSync, readFileSync } from 'node:fs'

// เขียน
const jsonOutput = JSON.stringify(rows, null, 2)
writeFileSync('employees.json', jsonOutput, 'utf8')

// อ่านกลับ
const parsed = JSON.parse(readFileSync('employees.json', 'utf8'))
console.log(Array.isArray(parsed))  // true
console.log(parsed[0].name)         // "สมชาย ใจดี"

เครื่องมือที่เกี่ยวข้อง

มีให้ในภาษาอื่นด้วย:Python
AC
Alex ChenFront-end & Node.js Developer

Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.

SL
Sophie Laurentผู้ตรวจสอบทางเทคนิค

Sophie is a full-stack developer focused on TypeScript across the entire stack — from React frontends to Express and Fastify backends. She has a particular interest in type-safe API design, runtime validation, and the patterns that make large JavaScript codebases stay manageable. She writes about TypeScript idioms, Node.js internals, and the ever-evolving JavaScript module ecosystem.