Trình phân tích cú pháp CSV được sử dụng trong trình cắm jquery-csv
Đây là một trình phân tích cú pháp ngữ pháp Chomsky Type III cơ bản .
Mã thông báo regex được sử dụng để đánh giá dữ liệu trên cơ sở char-by-char. Khi gặp char điều khiển, mã được chuyển đến câu lệnh chuyển đổi để đánh giá thêm dựa trên trạng thái bắt đầu. Các ký tự không điều khiển được nhóm và sao chép en masse để giảm số lượng thao tác sao chép chuỗi cần thiết.
Mã thông báo:
var tokenizer = /("|,|\n|\r|[^",\r\n]+)/;
Nhóm khớp đầu tiên là các ký tự điều khiển: dấu phân cách giá trị (") dấu phân cách giá trị (,) và dấu phân cách mục nhập (tất cả các biến thể của dòng mới). Trận đấu cuối xử lý nhóm char không kiểm soát.
Có 10 quy tắc mà trình phân tích cú pháp phải đáp ứng:
- Quy tắc số 1 - Một mục nhập trên mỗi dòng, mỗi dòng kết thúc bằng một dòng mới
- Quy tắc số 2 - Trailing dòng mới ở cuối tập tin bị bỏ qua
- Quy tắc số 3 - Hàng đầu tiên chứa dữ liệu tiêu đề
- Quy tắc số 4 - Không gian được coi là dữ liệu và các mục nhập không được chứa dấu phẩy
- Quy tắc số 5 - Các dòng có thể hoặc không được phân cách bằng dấu ngoặc kép
- Quy tắc số 6 - Các trường chứa dấu ngắt dòng, dấu ngoặc kép và dấu phẩy phải được đặt trong dấu ngoặc kép
- Quy tắc số 7 - Nếu trích dẫn kép được sử dụng để bao quanh các trường, thì một trích dẫn kép xuất hiện bên trong một trường phải được thoát bằng cách đặt trước nó bằng một trích dẫn kép khác
- Sửa đổi số 1 - Một trường không trích dẫn có thể hoặc có thể
- Sửa đổi số 2 - Một trường được trích dẫn có thể có hoặc không
- Sửa đổi số 3 - Trường cuối cùng trong mục nhập có thể có hoặc không chứa giá trị null
Lưu ý: 7 quy tắc hàng đầu được lấy trực tiếp từ IETF RFC 4180 . 3 cái cuối cùng đã được thêm vào để bao gồm các trường hợp cạnh được giới thiệu bởi các ứng dụng bảng tính hiện đại (ví dụ Excel, Bảng tính Google) không phân định (ví dụ như trích dẫn) tất cả các giá trị theo mặc định. Tôi đã cố gắng đóng góp lại các thay đổi cho RFC nhưng vẫn chưa nghe thấy phản hồi cho yêu cầu của tôi.
Đủ điều kiện, đây là sơ đồ:
Hoa Kỳ:
- trạng thái ban đầu cho một mục và / hoặc một giá trị
- một trích dẫn đã được bắt gặp
- một trích dẫn thứ hai đã được bắt gặp
- một giá trị chưa được trích dẫn đã gặp phải
Chuyển tiếp:
- a. kiểm tra cả giá trị được trích dẫn (1), giá trị không trích dẫn (3), giá trị null (0), mục nhập null (0) và mục nhập mới (0)
- b. kiểm tra một trích dẫn thứ hai char (2)
- c. kiểm tra báo giá đã thoát (1), kết thúc giá trị (0) và kết thúc mục nhập (0)
- d. kiểm tra kết thúc giá trị (0) và kết thúc mục nhập (0)
Lưu ý: Nó thực sự thiếu một trạng thái. Cần có một dòng từ 'c' -> 'b' được đánh dấu bằng trạng thái '1' vì một dấu phân cách thứ hai đã thoát có nghĩa là dấu phân cách thứ nhất vẫn đang mở. Trong thực tế, có lẽ sẽ tốt hơn nếu đại diện cho nó như là một quá trình chuyển đổi khác. Tạo ra chúng là một nghệ thuật, không có cách chính xác duy nhất.
Lưu ý: Nó cũng thiếu trạng thái thoát nhưng trên dữ liệu hợp lệ, trình phân tích cú pháp luôn kết thúc khi chuyển đổi 'a' và không có trạng thái nào khả thi vì không còn gì để phân tích.
Sự khác biệt giữa các quốc gia và quá trình chuyển đổi:
Một trạng thái là hữu hạn, có nghĩa là nó chỉ có thể được suy ra có nghĩa là một điều.
Một chuyển đổi đại diện cho dòng chảy giữa các trạng thái vì vậy nó có thể có nghĩa là nhiều thứ.
Về cơ bản, mối quan hệ chuyển đổi trạng thái-> là 1 -> * (tức là một-nhiều). Trạng thái xác định 'nó là gì' và quá trình chuyển đổi xác định 'cách xử lý'.
Lưu ý: Đừng lo lắng nếu việc áp dụng trạng thái / chuyển tiếp không cảm thấy trực quan, nó không trực quan. Phải mất một số tương ứng rộng rãi với ai đó thông minh hơn tôi nhiều trước khi cuối cùng tôi có khái niệm để gắn bó.
Mã giả:
csv = // csv input string
// init all state & data
state = 0
value = ""
entry = []
output = []
endOfValue() {
entry.push(value)
value = ""
}
endOfEntry() {
endOfValue()
output.push(entry)
entry = []
}
tokenizer = /("|,|\n|\r|[^",\r\n]+)/gm
// using the match extension of string.replace. string.exec can also be used in a similar manner
csv.replace(tokenizer, function (match) {
switch(state) {
case 0:
if(opening delimiter)
state = 1
break
if(new-line)
endOfEntry()
state = 0
break
if(un-delimited data)
value += match
state = 3
break
case 1:
if(second delimiter encountered)
state = 2
break
if(non-control char data)
value += match
state = 1
break
case 2:
if(escaped delimiter)
state = 1
break
if(separator)
endOfValue()
state = 0
break
if(newline)
endOfEntry()
state = 0
break
case 3:
if(separator)
endOfValue()
state = 0
break
if(newline)
endOfEntry()
state = 0
break
}
}
Lưu ý: Đây là ý chính, trong thực tế có rất nhiều điều cần xem xét. Ví dụ: kiểm tra lỗi, giá trị null, một dòng trống ở cuối (nghĩa là hợp lệ), v.v.
Trong trường hợp này, trạng thái là điều kiện của mọi thứ khi khối kết hợp biểu thức chính quy kết thúc một lần lặp. Việc chuyển đổi được thể hiện dưới dạng các báo cáo trường hợp.
Là con người, chúng ta có xu hướng đơn giản hóa các hoạt động cấp thấp thành các tóm tắt cấp cao hơn nhưng làm việc với một FSM đang hoạt động với các hoạt động cấp thấp. Mặc dù các trạng thái và chuyển tiếp rất dễ dàng để làm việc với từng cá nhân, nhưng về cơ bản, rất khó để hình dung toàn bộ tất cả cùng một lúc. Tôi thấy dễ dàng nhất để đi theo từng con đường thực hiện lặp đi lặp lại cho đến khi tôi có thể hiểu được cách chuyển đổi diễn ra. Đó là vua thích học toán cơ bản, bạn sẽ không thể đánh giá mã từ cấp cao hơn cho đến khi các chi tiết cấp thấp bắt đầu trở nên tự động.
Ngoài ra: Nếu bạn nhìn vào thực hiện thực tế, có rất nhiều chi tiết bị thiếu. Đầu tiên, tất cả các con đường không thể sẽ ném ngoại lệ cụ thể. Không thể đánh chúng nhưng nếu bất cứ điều gì phá vỡ chúng sẽ hoàn toàn kích hoạt ngoại lệ trong người chạy thử. Thứ hai, các quy tắc của trình phân tích cú pháp cho những gì được phép trong chuỗi dữ liệu CSV 'hợp pháp' khá lỏng lẻo nên mã cần thiết để xử lý nhiều trường hợp cạnh cụ thể. Bất kể thực tế đó, đây là quá trình được sử dụng để chế nhạo FSM trước tất cả các sửa lỗi, tiện ích mở rộng và tinh chỉnh.
Như với hầu hết các thiết kế, nó không phải là một đại diện chính xác của việc thực hiện nhưng nó phác thảo các phần quan trọng. Trong thực tế, thực tế có 3 hàm phân tích cú pháp khác nhau xuất phát từ thiết kế này: bộ tách dòng cụ thể csv, trình phân tích cú pháp một dòng và trình phân tích cú pháp nhiều dòng hoàn chỉnh. Tất cả đều hoạt động theo cách tương tự, chúng khác nhau ở cách chúng xử lý ký tự dòng mới.