Skip to content

Commit deb4ef6

Browse files
Ophirr33AndyGauge
authored andcommitted
initial csv-transform (#348)
* typos * initial csv-transform changed url parsing into color parsing * hid boilerplate and added some more documentation
1 parent 50b184c commit deb4ef6

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

src/encoding.md

+106-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
| [Handle invalid CSV data with Serde][ex-invalid-csv] | [![csv-badge]][csv] [![serde-badge]][serde] | [![cat-encoding-badge]][cat-encoding] |
1515
| [Serialize records to CSV][ex-serialize-csv] | [![csv-badge]][csv] | [![cat-encoding-badge]][cat-encoding] |
1616
| [Serialize records to CSV using Serde][ex-csv-serde] | [![csv-badge]][csv] [![serde-badge]][serde] | [![cat-encoding-badge]][cat-encoding] |
17+
| [Transform one column of a CSV file][ex-csv-transform-column] | [![csv-badge]][csv] [![serde-badge]][serde] | [![cat-encoding-badge]][cat-encoding] |
1718
| [Get MIME type from string][ex-mime-from-string] | [![mime-badge]][mime] | [![cat-encoding-badge]][cat-encoding] |
1819

1920
[ex-json-value]: #ex-json-value
@@ -688,6 +689,107 @@ fn run() -> Result<()> {
688689
#
689690
# quick_main!(run);
690691
```
692+
[ex-csv-transform-column]: #ex-csv-transform-column
693+
<a name="ex-csv-transform-column"></a>
694+
## Transform CSV column
695+
696+
[![csv-badge]][csv] [![serde-badge]][serde] [![cat-encoding-badge]][cat-encoding]
697+
698+
Transform a CSV file containing a color name and a hex color into one with a
699+
color name and an rgb color. Utilizes the [csv] crate to read and write the
700+
csv file, and [serde] to deserialize and serialize the rows to and from bytes.
701+
702+
See [`csv::Reader::deserialize`], [`serde::Deserialize`], and [`std::str::FromStr`]
703+
704+
```rust
705+
extern crate csv;
706+
# #[macro_use]
707+
# extern crate error_chain;
708+
#[macro_use]
709+
extern crate serde_derive;
710+
extern crate serde;
711+
712+
use csv::{Reader, Writer};
713+
use serde::{de, Deserialize, Deserializer};
714+
use std::str::FromStr;
715+
#
716+
# error_chain! {
717+
# foreign_links {
718+
# CsvError(csv::Error);
719+
# ParseInt(std::num::ParseIntError);
720+
# CsvInnerError(csv::IntoInnerError<Writer<Vec<u8>>>);
721+
# IO(std::fmt::Error);
722+
# UTF8(std::string::FromUtf8Error);
723+
# }
724+
# }
725+
726+
#[derive(Debug)]
727+
struct HexColor {
728+
red: u8,
729+
green: u8,
730+
blue: u8,
731+
}
732+
733+
#[derive(Debug, Deserialize)]
734+
struct Row {
735+
color_name: String,
736+
color: HexColor,
737+
}
738+
739+
impl FromStr for HexColor {
740+
type Err = Error;
741+
742+
fn from_str(hex_color: &str) -> std::result::Result<Self, Self::Err> {
743+
let trimmed = hex_color.trim_matches('#');
744+
if trimmed.len() != 6 {
745+
Err("Invalid length of hex string".into())
746+
} else {
747+
Ok(HexColor {
748+
red: u8::from_str_radix(&trimmed[..2], 16)?,
749+
green: u8::from_str_radix(&trimmed[2..4], 16)?,
750+
blue: u8::from_str_radix(&trimmed[4..6], 16)?,
751+
})
752+
}
753+
}
754+
}
755+
756+
impl<'de> Deserialize<'de> for HexColor {
757+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
758+
where
759+
D: Deserializer<'de>,
760+
{
761+
let s = String::deserialize(deserializer)?;
762+
FromStr::from_str(&s).map_err(de::Error::custom)
763+
}
764+
}
765+
766+
fn run() -> Result<()> {
767+
let data = "color_name,color
768+
red,#ff0000
769+
green,#00ff00
770+
blue,#0000FF
771+
periwinkle,#ccccff
772+
magenta,#ff00ff"
773+
.to_owned();
774+
let mut out = Writer::from_writer(vec![]);
775+
let mut reader = Reader::from_reader(data.as_bytes());
776+
for result in reader.deserialize::<Row>() {
777+
let res = result?;
778+
out.serialize((
779+
res.color_name,
780+
res.color.red,
781+
res.color.green,
782+
res.color.blue,
783+
))?;
784+
}
785+
let written = String::from_utf8(out.into_inner()?)?;
786+
assert_eq!(Some("magenta,255,0,255"), written.lines().last());
787+
println!("{}", written);
788+
Ok(())
789+
}
790+
#
791+
# quick_main!(run);
792+
```
691793

692794
[ex-mime-from-string]: #ex-mime-from-string
693795
<a name="ex-mime-from-string"></a>
@@ -729,17 +831,20 @@ fn main() {
729831
<!-- API Reference -->
730832

731833
[`csv::ByteRecord`]: https://docs.rs/csv/*/csv/struct.ByteRecord.html
732-
[`csv::invalid_option`]: https://docs.rs/csv/*/csv/fn.invalid_option.html
733834
[`csv::Reader::deserialize`]: https://docs.rs/csv/*/csv/struct.Reader.html#method.deserialize
835+
[`csv::Reader::deserialize`]: https://docs.rs/csv/\*/csv/struct.Reader.html#method.deserialize
734836
[`csv::StringRecord`]: https://docs.rs/csv/*/csv/struct.StringRecord.html
735837
[`csv::Writer`]: https://docs.rs/csv/*/csv/struct.Writer.html
838+
[`csv::invalid_option`]: https://docs.rs/csv/*/csv/fn.invalid_option.html
736839
[`flush`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.flush
737840
[`form_urlencoded::byte_serialize`]: https://docs.rs/url/*/url/form_urlencoded/fn.byte_serialize.html
738841
[`form_urlencoded::parse`]: https://docs.rs/url/*/url/form_urlencoded/fn.parse.html
739842
[`FromStrError`]: https://docs.rs/mime/*/mime/struct.FromStrError.html
740843
[`MIME`]: https://docs.rs/mime/*/mime/struct.Mime.html
741844
[`percent_decode`]: https://docs.rs/url/*/url/percent_encoding/fn.percent_decode.html
845+
[`serde::Deserialize`]: https://docs.rs/serde/\*/serde/trait.Deserialize.html
742846
[`serialize`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.serialize
847+
[`std::str::FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
743848
[`utf8_percent_encode`]: https://docs.rs/url/*/url/percent_encoding/fn.utf8_percent_encode.html
744849
[`write_record`]: https://docs.rs/csv/*/csv/struct.Writer.html#method.write_record
745850

src/intro.md

+2
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ community. It needs and welcomes help. For details see
7474
| [Handle invalid CSV data with Serde][ex-invalid-csv] | [![csv-badge]][csv] [![serde-badge]][serde] | [![cat-encoding-badge]][cat-encoding] |
7575
| [Serialize records to CSV][ex-serialize-csv] | [![csv-badge]][csv] | [![cat-encoding-badge]][cat-encoding] |
7676
| [Serialize records to CSV using Serde][ex-csv-serde] | [![csv-badge]][csv] [![serde-badge]][serde] | [![cat-encoding-badge]][cat-encoding] |
77+
| [Transform one column of a CSV file][ex-csv-transform-column] | [![csv-badge]][csv] [![serde-badge]][serde] | [![cat-encoding-badge]][cat-encoding] |
7778
| [Get MIME type from string][ex-mime-from-string] | [![mime-badge]][mime] | [![cat-encoding-badge]][cat-encoding] |
7879

7980
## [Concurrency](concurrency.html)
@@ -177,6 +178,7 @@ community. It needs and welcomes help. For details see
177178
[ex-convert-datetime-timestamp]: basics.html#ex-convert-datetime-timestamp
178179
[ex-convert-datetime-timezone]: basics.html#ex-convert-datetime-timezone
179180
[ex-crossbeam-spawn]: concurrency.html#ex-crossbeam-spawn
181+
[ex-csv-transform-column]: encoding.html#ex-csv-transform-column
180182
[ex-csv-delimiter]: encoding.html#ex-csv-delimiter
181183
[ex-csv-filter]: encoding.html#ex-csv-filter
182184
[ex-csv-read]: encoding.html#ex-csv-read

0 commit comments

Comments
 (0)