use super::core::Series;
use crate::error::AxionResult;
use crate::dtype::DataType;
pub struct StringAccessor<'a> {
series: &'a Series<String>,
}
impl<'a> StringAccessor<'a> {
pub(super) fn new(series: &'a Series<String>) -> Self {
assert_eq!(series.dtype(), DataType::String, "StringAccessor can only be used on Series<String>");
Self { series }
}
pub fn contains(&self, pattern: &str) -> AxionResult<Series<bool>> {
let new_name = format!("{}_contains_{}", self.series.name(), pattern);
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::Bool));
}
let new_data: Vec<Option<bool>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.contains(pattern)))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn startswith(&self, pattern: &str) -> AxionResult<Series<bool>> {
let new_name = format!("{}_startswith_{}", self.series.name(), pattern);
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::Bool));
}
let new_data: Vec<Option<bool>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.starts_with(pattern)))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn endswith(&self, pattern: &str) -> AxionResult<Series<bool>> {
let new_name = format!("{}_endswith_{}", self.series.name(), pattern);
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::Bool));
}
let new_data: Vec<Option<bool>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.ends_with(pattern)))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn str_len(&self) -> AxionResult<Series<u32>> {
let new_name = format!("{}_len", self.series.name());
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::UInt32));
}
let new_data: Vec<Option<u32>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.len() as u32))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn replace(&self, from: &str, to: &str) -> AxionResult<Series<String>> {
let new_name = format!("{}_replace", self.series.name());
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::String));
}
let new_data: Vec<Option<String>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.replace(from, to)))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn to_lowercase(&self) -> AxionResult<Series<String>> {
let new_name = format!("{}_lower", self.series.name());
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::String));
}
let new_data: Vec<Option<String>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.to_lowercase()))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn to_uppercase(&self) -> AxionResult<Series<String>> {
let new_name = format!("{}_upper", self.series.name());
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::String));
}
let new_data: Vec<Option<String>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.to_uppercase()))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn strip(&self) -> AxionResult<Series<String>> {
let new_name = format!("{}_strip", self.series.name());
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::String));
}
let new_data: Vec<Option<String>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.trim().to_string()))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn lstrip(&self) -> AxionResult<Series<String>> {
let new_name = format!("{}_lstrip", self.series.name());
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::String));
}
let new_data: Vec<Option<String>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.trim_start().to_string()))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
pub fn rstrip(&self) -> AxionResult<Series<String>> {
let new_name = format!("{}_rstrip", self.series.name());
if self.series.is_empty() {
return Ok(Series::new_empty(new_name, DataType::String));
}
let new_data: Vec<Option<String>> = self.series.data.iter()
.map(|opt_s| opt_s.as_ref().map(|s| s.trim_end().to_string()))
.collect();
Ok(Series::new_from_options(new_name, new_data))
}
}