Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions src/nyacsv.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,20 @@ struct CSV {
rows : Array[Array[String]]
}

///| header of the CSV.
///|
/// header of the CSV.
pub fn CSV::header(self : CSV) -> Array[String] {
self.headers
}

///| data of the CSV.
///|
/// data of the CSV.
pub fn CSV::data(self : CSV) -> Array[Array[String]] {
self.rows
}

///| shape of the CSV.
///|
/// shape of the CSV.
pub fn CSV::shape(self : CSV) -> (Int, Int) {
let row_count = self.rows.length()
let column_count = if row_count > 0 { self.rows[0].length() } else { 0 }
Expand Down Expand Up @@ -191,8 +194,8 @@ pub fn CSV::new() -> CSV {
///|
pub fn CSV::from_array(
data : Array[Array[String]],
has_header~ : Bool = true,
generate_headers~ : Bool = true,
has_header? : Bool = true,
generate_headers? : Bool = true,
) -> CSV {
if data.is_empty() {
CSV::new()
Expand Down Expand Up @@ -232,7 +235,7 @@ pub fn CSV::from_array(
/// first row and subsequent rows as data.
pub fn CSV::parse_string(
data : String,
options~ : CSVOptions = {
options? : CSVOptions = {
delimiter: ',',
allow_newlines_in_quotes: true,
quote_char: '"',
Expand Down Expand Up @@ -274,7 +277,7 @@ test "CSV::parse_buffer/basic" {
/// first row and subsequent rows as data.
pub fn CSV::parse_buffer(
data : @buffer.Buffer,
options~ : CSVOptions = {
options? : CSVOptions = {
delimiter: ',',
allow_newlines_in_quotes: true,
quote_char: '"',
Expand Down Expand Up @@ -310,7 +313,7 @@ pub fn CSV::parse_buffer(
/// first row and subsequent rows as data.
pub fn CSV::parse_bytes(
data : Bytes,
options~ : CSVOptions = {
options? : CSVOptions = {
delimiter: ',',
allow_newlines_in_quotes: true,
quote_char: '"',
Expand Down
19 changes: 5 additions & 14 deletions src/nyacsv_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ test "CSV::from_array/first_row_empty" {
}

///|
test "CSV::from_array/first_row_empty_with_header" {
test "CSV::from_array/first_row_empty_with_header_no_generate" {
// 测试把空行当作表头的情况
let data : Array[Array[String]] = [
[], // 空表头行
Expand Down Expand Up @@ -144,17 +144,6 @@ test "CSV::parse_string/quoted_with_internal_quotes" {
assert_eq(csv.data()[0][1], "ha \"ha\" ha")
}

///|
test "CSV::parse_string/quoted_with_internal_quotes" {
let data = "a,b\n1,\"ha \"\"ha\"\" ha\"\n3,4\n"
let csv = CSV::parse_string(data)
inspect(csv.header(), content="[\"a\", \"b\"]")
inspect(csv.data(), content="[[\"1\", \"ha \\\"ha\\\" ha\"], [\"3\", \"4\"]]")

// 验证内部引号正确处理
assert_eq(csv.data()[0][1], "ha \"ha\" ha")
}

///|
test "CSV::parse_string/json_in_field" {
let data = "key,val\n1,\"{\"\"type\"\": \"\"Point\"\", \"\"coordinates\"\": [102.0, 0.5]}\"\n"
Expand Down Expand Up @@ -234,7 +223,8 @@ test "CSV::parse_string/custom_delimiter" {
assert_eq(csv.data()[0][2], "120 any st., Anytown")
}

///| Test for empty bytes input.
///|
/// Test for empty bytes input.
test "@nyacsv.CSV::parse_bytes/empty_bytes" {
let data = Bytes::new(0) // Create an empty byte sequence.
let csv = @NyaCSV.CSV::parse_bytes(data) // Call the `parse_bytes` function with empty data.
Expand All @@ -243,7 +233,8 @@ test "@nyacsv.CSV::parse_bytes/empty_bytes" {
inspect(csv.data(), content="[]")
}

///| Test for a single line of data with no header.
///|
/// Test for a single line of data with no header.
test "@nyacsv.CSV::parse_bytes/single_line_no_header" {
// Create a byte sequence representing a single line of data values separated by commas.
let data = @encoding/utf8.encode("value1,value2,value3")
Expand Down
26 changes: 4 additions & 22 deletions src/parser.mbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///|
fn[T : CSVReader] parse(
reader : T,
options~ : CSVOptions = {
options? : CSVOptions = {
delimiter: ',',
allow_newlines_in_quotes: true,
quote_char: '"',
Expand Down Expand Up @@ -79,31 +79,15 @@ fn[T : CSVReader] parse(
} else if ch == options.delimiter {
// 遇到分隔符,当前字段结束
if options.trim_spaces {
row.push(
field
.to_string()
.trim(char_set="\n")
.trim(char_set="\r")
.trim(char_set="\t")
.trim(char_set=" ")
.to_string(),
)
row.push(field.to_string().trim(char_set="\n\r\t ").to_string())
} else {
row.push(field.to_string())
}
field = StringBuilder::new() // 创建新的字段构建器
} else if ch == '\n' {
// 遇到换行且不在引号内,当前记录结束
if options.trim_spaces {
row.push(
field
.to_string()
.trim(char_set="\n")
.trim(char_set="\r")
.trim(char_set="\t")
.trim(char_set=" ")
.to_string(),
)
row.push(field.to_string().trim(char_set="\n\r\t ").to_string())
} else {
row.push(field.to_string())
}
Expand All @@ -125,9 +109,7 @@ fn[T : CSVReader] parse(
// 循环结束后,加入最后的字段和行(如果有)
if not(field.is_empty()) || row.length() > 0 {
if options.trim_spaces {
row.push(
field.to_string().trim(char_set="\n").trim(char_set="\r").trim(char_set="\t").trim(char_set=" ").to_string(),
)
row.push(field.to_string().trim(char_set="\n\r\t ").to_string())
} else {
row.push(field.to_string())
}
Expand Down
35 changes: 35 additions & 0 deletions src/pkg.generated.mbti
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Generated using `moon info`, DON'T EDIT IT
package "xunyoyo/NyaCSV"

import(
"moonbitlang/core/buffer"
)

// Values

// Errors

// Types and methods
type CSV
pub fn CSV::data(Self) -> Array[Array[String]]
pub fn CSV::from_array(Array[Array[String]], has_header? : Bool, generate_headers? : Bool) -> Self
pub fn CSV::header(Self) -> Array[String]
pub fn CSV::new() -> Self
pub fn CSV::parse_buffer(@buffer.Buffer, options? : CSVOptions) -> Self
pub fn CSV::parse_bytes(Bytes, options? : CSVOptions) -> Self
pub fn CSV::parse_string(String, options? : CSVOptions) -> Self
pub fn CSV::shape(Self) -> (Int, Int)
pub impl Show for CSV

pub(all) struct CSVOptions {
delimiter : Char
allow_newlines_in_quotes : Bool
quote_char : Char
skip_empty_lines : Bool
trim_spaces : Bool
}

// Type aliases

// Traits

4 changes: 2 additions & 2 deletions src/reader.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ priv struct StringReader {
///|
impl CSVReader for StringReader with read_char(self) -> Char? {
if self.pos < self.source.length() {
let ch = Int::unsafe_to_char(self.source[self.pos])
let ch = Int::unsafe_to_char(self.source.code_unit_at(self.pos).to_int())
self.pos += 1
Some(ch)
} else {
Expand Down Expand Up @@ -69,7 +69,7 @@ test "StringReader::read_char/past_end_of_string" {
///|
impl CSVReader for StringReader with peek_char(self) -> Char? {
if self.pos < self.source.length() {
Some(Int::unsafe_to_char(self.source[self.pos]))
Some(Int::unsafe_to_char(self.source.code_unit_at(self.pos).to_int()))
} else {
None
}
Expand Down