axion_data/series/
string.rs1use super::core::Series;
2use crate::error::AxionResult;
3use crate::dtype::DataType;
4
5pub struct StringAccessor<'a> {
22 series: &'a Series<String>,
23}
24
25impl<'a> StringAccessor<'a> {
26 pub(super) fn new(series: &'a Series<String>) -> Self {
36 assert_eq!(series.dtype(), DataType::String, "StringAccessor can only be used on Series<String>");
37 Self { series }
38 }
39
40 pub fn contains(&self, pattern: &str) -> AxionResult<Series<bool>> {
50 let new_name = format!("{}_contains_{}", self.series.name(), pattern);
51 if self.series.is_empty() {
52 return Ok(Series::new_empty(new_name, DataType::Bool));
53 }
54 let new_data: Vec<Option<bool>> = self.series.data.iter()
55 .map(|opt_s| opt_s.as_ref().map(|s| s.contains(pattern)))
56 .collect();
57 Ok(Series::new_from_options(new_name, new_data))
58 }
59
60 pub fn startswith(&self, pattern: &str) -> AxionResult<Series<bool>> {
70 let new_name = format!("{}_startswith_{}", self.series.name(), pattern);
71 if self.series.is_empty() {
72 return Ok(Series::new_empty(new_name, DataType::Bool));
73 }
74 let new_data: Vec<Option<bool>> = self.series.data.iter()
75 .map(|opt_s| opt_s.as_ref().map(|s| s.starts_with(pattern)))
76 .collect();
77 Ok(Series::new_from_options(new_name, new_data))
78 }
79
80 pub fn endswith(&self, pattern: &str) -> AxionResult<Series<bool>> {
90 let new_name = format!("{}_endswith_{}", self.series.name(), pattern);
91 if self.series.is_empty() {
92 return Ok(Series::new_empty(new_name, DataType::Bool));
93 }
94 let new_data: Vec<Option<bool>> = self.series.data.iter()
95 .map(|opt_s| opt_s.as_ref().map(|s| s.ends_with(pattern)))
96 .collect();
97 Ok(Series::new_from_options(new_name, new_data))
98 }
99
100 pub fn str_len(&self) -> AxionResult<Series<u32>> {
106 let new_name = format!("{}_len", self.series.name());
107 if self.series.is_empty() {
108 return Ok(Series::new_empty(new_name, DataType::UInt32));
109 }
110 let new_data: Vec<Option<u32>> = self.series.data.iter()
111 .map(|opt_s| opt_s.as_ref().map(|s| s.len() as u32))
112 .collect();
113 Ok(Series::new_from_options(new_name, new_data))
114 }
115
116 pub fn replace(&self, from: &str, to: &str) -> AxionResult<Series<String>> {
127 let new_name = format!("{}_replace", self.series.name());
128 if self.series.is_empty() {
129 return Ok(Series::new_empty(new_name, DataType::String));
130 }
131 let new_data: Vec<Option<String>> = self.series.data.iter()
132 .map(|opt_s| opt_s.as_ref().map(|s| s.replace(from, to)))
133 .collect();
134 Ok(Series::new_from_options(new_name, new_data))
135 }
136
137 pub fn to_lowercase(&self) -> AxionResult<Series<String>> {
143 let new_name = format!("{}_lower", self.series.name());
144 if self.series.is_empty() {
145 return Ok(Series::new_empty(new_name, DataType::String));
146 }
147 let new_data: Vec<Option<String>> = self.series.data.iter()
148 .map(|opt_s| opt_s.as_ref().map(|s| s.to_lowercase()))
149 .collect();
150 Ok(Series::new_from_options(new_name, new_data))
151 }
152
153 pub fn to_uppercase(&self) -> AxionResult<Series<String>> {
159 let new_name = format!("{}_upper", self.series.name());
160 if self.series.is_empty() {
161 return Ok(Series::new_empty(new_name, DataType::String));
162 }
163 let new_data: Vec<Option<String>> = self.series.data.iter()
164 .map(|opt_s| opt_s.as_ref().map(|s| s.to_uppercase()))
165 .collect();
166 Ok(Series::new_from_options(new_name, new_data))
167 }
168
169 pub fn strip(&self) -> AxionResult<Series<String>> {
175 let new_name = format!("{}_strip", self.series.name());
176 if self.series.is_empty() {
177 return Ok(Series::new_empty(new_name, DataType::String));
178 }
179 let new_data: Vec<Option<String>> = self.series.data.iter()
180 .map(|opt_s| opt_s.as_ref().map(|s| s.trim().to_string()))
181 .collect();
182 Ok(Series::new_from_options(new_name, new_data))
183 }
184
185 pub fn lstrip(&self) -> AxionResult<Series<String>> {
191 let new_name = format!("{}_lstrip", self.series.name());
192 if self.series.is_empty() {
193 return Ok(Series::new_empty(new_name, DataType::String));
194 }
195 let new_data: Vec<Option<String>> = self.series.data.iter()
196 .map(|opt_s| opt_s.as_ref().map(|s| s.trim_start().to_string()))
197 .collect();
198 Ok(Series::new_from_options(new_name, new_data))
199 }
200
201 pub fn rstrip(&self) -> AxionResult<Series<String>> {
207 let new_name = format!("{}_rstrip", self.series.name());
208 if self.series.is_empty() {
209 return Ok(Series::new_empty(new_name, DataType::String));
210 }
211 let new_data: Vec<Option<String>> = self.series.data.iter()
212 .map(|opt_s| opt_s.as_ref().map(|s| s.trim_end().to_string()))
213 .collect();
214 Ok(Series::new_from_options(new_name, new_data))
215 }
216}