polars_python/expr/
string.rs

1use polars::prelude::*;
2use pyo3::prelude::*;
3
4use super::datatype::PyDataTypeExpr;
5use crate::PyExpr;
6use crate::conversion::Wrap;
7use crate::error::PyPolarsErr;
8
9#[pymethods]
10impl PyExpr {
11    fn str_join(&self, delimiter: &str, ignore_nulls: bool) -> Self {
12        self.inner
13            .clone()
14            .str()
15            .join(delimiter, ignore_nulls)
16            .into()
17    }
18
19    #[pyo3(signature = (format, strict, exact, cache))]
20    fn str_to_date(&self, format: Option<String>, strict: bool, exact: bool, cache: bool) -> Self {
21        let format = format.map(|x| x.into());
22
23        let options = StrptimeOptions {
24            format,
25            strict,
26            exact,
27            cache,
28        };
29        self.inner.clone().str().to_date(options).into()
30    }
31
32    #[pyo3(signature = (format, time_unit, time_zone, strict, exact, cache, ambiguous))]
33    fn str_to_datetime(
34        &self,
35        format: Option<String>,
36        time_unit: Option<Wrap<TimeUnit>>,
37        time_zone: Wrap<Option<TimeZone>>,
38        strict: bool,
39        exact: bool,
40        cache: bool,
41        ambiguous: Self,
42    ) -> Self {
43        let format = format.map(|x| x.into());
44        let time_zone = time_zone.0;
45
46        let options = StrptimeOptions {
47            format,
48            strict,
49            exact,
50            cache,
51        };
52        self.inner
53            .clone()
54            .str()
55            .to_datetime(
56                time_unit.map(|tu| tu.0),
57                time_zone,
58                options,
59                ambiguous.inner,
60            )
61            .into()
62    }
63
64    #[pyo3(signature = (format, strict, cache))]
65    fn str_to_time(&self, format: Option<String>, strict: bool, cache: bool) -> Self {
66        let format = format.map(|x| x.into());
67
68        let options = StrptimeOptions {
69            format,
70            strict,
71            cache,
72            exact: true,
73        };
74        self.inner.clone().str().to_time(options).into()
75    }
76
77    fn str_strip_chars(&self, matches: Self) -> Self {
78        self.inner.clone().str().strip_chars(matches.inner).into()
79    }
80
81    fn str_strip_chars_start(&self, matches: Self) -> Self {
82        self.inner
83            .clone()
84            .str()
85            .strip_chars_start(matches.inner)
86            .into()
87    }
88
89    fn str_strip_chars_end(&self, matches: Self) -> Self {
90        self.inner
91            .clone()
92            .str()
93            .strip_chars_end(matches.inner)
94            .into()
95    }
96
97    fn str_strip_prefix(&self, prefix: Self) -> Self {
98        self.inner.clone().str().strip_prefix(prefix.inner).into()
99    }
100
101    fn str_strip_suffix(&self, suffix: Self) -> Self {
102        self.inner.clone().str().strip_suffix(suffix.inner).into()
103    }
104
105    fn str_slice(&self, offset: Self, length: Self) -> Self {
106        self.inner
107            .clone()
108            .str()
109            .slice(offset.inner, length.inner)
110            .into()
111    }
112
113    fn str_head(&self, n: Self) -> Self {
114        self.inner.clone().str().head(n.inner).into()
115    }
116
117    fn str_tail(&self, n: Self) -> Self {
118        self.inner.clone().str().tail(n.inner).into()
119    }
120
121    fn str_to_uppercase(&self) -> Self {
122        self.inner.clone().str().to_uppercase().into()
123    }
124
125    fn str_to_lowercase(&self) -> Self {
126        self.inner.clone().str().to_lowercase().into()
127    }
128
129    #[cfg(feature = "nightly")]
130    fn str_to_titlecase(&self) -> Self {
131        self.inner.clone().str().to_titlecase().into()
132    }
133
134    fn str_len_bytes(&self) -> Self {
135        self.inner.clone().str().len_bytes().into()
136    }
137
138    fn str_len_chars(&self) -> Self {
139        self.inner.clone().str().len_chars().into()
140    }
141
142    #[cfg(feature = "regex")]
143    fn str_replace_n(&self, pat: Self, val: Self, literal: bool, n: i64) -> Self {
144        self.inner
145            .clone()
146            .str()
147            .replace_n(pat.inner, val.inner, literal, n)
148            .into()
149    }
150
151    #[cfg(feature = "regex")]
152    fn str_replace_all(&self, pat: Self, val: Self, literal: bool) -> Self {
153        self.inner
154            .clone()
155            .str()
156            .replace_all(pat.inner, val.inner, literal)
157            .into()
158    }
159
160    fn str_normalize(&self, form: Wrap<UnicodeForm>) -> Self {
161        self.inner.clone().str().normalize(form.0).into()
162    }
163
164    fn str_reverse(&self) -> Self {
165        self.inner.clone().str().reverse().into()
166    }
167
168    fn str_pad_start(&self, length: usize, fill_char: char) -> Self {
169        self.inner.clone().str().pad_start(length, fill_char).into()
170    }
171
172    fn str_pad_end(&self, length: usize, fill_char: char) -> Self {
173        self.inner.clone().str().pad_end(length, fill_char).into()
174    }
175
176    fn str_zfill(&self, length: Self) -> Self {
177        self.inner.clone().str().zfill(length.inner).into()
178    }
179
180    #[pyo3(signature = (pat, literal, strict))]
181    #[cfg(feature = "regex")]
182    fn str_contains(&self, pat: Self, literal: Option<bool>, strict: bool) -> Self {
183        match literal {
184            Some(true) => self.inner.clone().str().contains_literal(pat.inner).into(),
185            _ => self.inner.clone().str().contains(pat.inner, strict).into(),
186        }
187    }
188
189    #[pyo3(signature = (pat, literal, strict))]
190    #[cfg(feature = "regex")]
191    fn str_find(&self, pat: Self, literal: Option<bool>, strict: bool) -> Self {
192        match literal {
193            Some(true) => self.inner.clone().str().find_literal(pat.inner).into(),
194            _ => self.inner.clone().str().find(pat.inner, strict).into(),
195        }
196    }
197
198    fn str_ends_with(&self, sub: Self) -> Self {
199        self.inner.clone().str().ends_with(sub.inner).into()
200    }
201
202    fn str_starts_with(&self, sub: Self) -> Self {
203        self.inner.clone().str().starts_with(sub.inner).into()
204    }
205
206    fn str_hex_encode(&self) -> Self {
207        self.inner.clone().str().hex_encode().into()
208    }
209
210    #[cfg(feature = "binary_encoding")]
211    fn str_hex_decode(&self, strict: bool) -> Self {
212        self.inner.clone().str().hex_decode(strict).into()
213    }
214
215    fn str_base64_encode(&self) -> Self {
216        self.inner.clone().str().base64_encode().into()
217    }
218
219    #[cfg(feature = "binary_encoding")]
220    fn str_base64_decode(&self, strict: bool) -> Self {
221        self.inner.clone().str().base64_decode(strict).into()
222    }
223
224    fn str_to_integer(&self, base: Self, strict: bool) -> Self {
225        self.inner
226            .clone()
227            .str()
228            .to_integer(base.inner, strict)
229            .into()
230    }
231
232    #[cfg(feature = "extract_jsonpath")]
233    #[pyo3(signature = (dtype=None, infer_schema_len=None))]
234    fn str_json_decode(
235        &self,
236        dtype: Option<PyDataTypeExpr>,
237        infer_schema_len: Option<usize>,
238    ) -> Self {
239        let dtype = dtype.map(|wrap| wrap.inner);
240        self.inner
241            .clone()
242            .str()
243            .json_decode(dtype, infer_schema_len)
244            .into()
245    }
246
247    #[cfg(feature = "extract_jsonpath")]
248    fn str_json_path_match(&self, pat: Self) -> Self {
249        self.inner.clone().str().json_path_match(pat.inner).into()
250    }
251
252    fn str_extract(&self, pat: Self, group_index: usize) -> Self {
253        self.inner
254            .clone()
255            .str()
256            .extract(pat.inner, group_index)
257            .into()
258    }
259
260    fn str_extract_all(&self, pat: Self) -> Self {
261        self.inner.clone().str().extract_all(pat.inner).into()
262    }
263
264    #[cfg(feature = "extract_groups")]
265    fn str_extract_groups(&self, pat: &str) -> PyResult<Self> {
266        Ok(self
267            .inner
268            .clone()
269            .str()
270            .extract_groups(pat)
271            .map_err(PyPolarsErr::from)?
272            .into())
273    }
274
275    fn str_count_matches(&self, pat: Self, literal: bool) -> Self {
276        self.inner
277            .clone()
278            .str()
279            .count_matches(pat.inner, literal)
280            .into()
281    }
282
283    fn str_split(&self, by: Self) -> Self {
284        self.inner.clone().str().split(by.inner).into()
285    }
286
287    fn str_split_inclusive(&self, by: Self) -> Self {
288        self.inner.clone().str().split_inclusive(by.inner).into()
289    }
290
291    fn str_split_exact(&self, by: Self, n: usize) -> Self {
292        self.inner.clone().str().split_exact(by.inner, n).into()
293    }
294
295    fn str_split_exact_inclusive(&self, by: Self, n: usize) -> Self {
296        self.inner
297            .clone()
298            .str()
299            .split_exact_inclusive(by.inner, n)
300            .into()
301    }
302
303    fn str_splitn(&self, by: Self, n: usize) -> Self {
304        self.inner.clone().str().splitn(by.inner, n).into()
305    }
306
307    fn str_to_decimal(&self, infer_len: usize) -> Self {
308        self.inner.clone().str().to_decimal(infer_len).into()
309    }
310
311    #[cfg(feature = "find_many")]
312    fn str_contains_any(&self, patterns: PyExpr, ascii_case_insensitive: bool) -> Self {
313        self.inner
314            .clone()
315            .str()
316            .contains_any(patterns.inner, ascii_case_insensitive)
317            .into()
318    }
319    #[cfg(feature = "find_many")]
320    fn str_replace_many(
321        &self,
322        patterns: PyExpr,
323        replace_with: PyExpr,
324        ascii_case_insensitive: bool,
325    ) -> Self {
326        self.inner
327            .clone()
328            .str()
329            .replace_many(patterns.inner, replace_with.inner, ascii_case_insensitive)
330            .into()
331    }
332
333    #[cfg(feature = "find_many")]
334    fn str_extract_many(
335        &self,
336        patterns: PyExpr,
337        ascii_case_insensitive: bool,
338        overlapping: bool,
339    ) -> Self {
340        self.inner
341            .clone()
342            .str()
343            .extract_many(patterns.inner, ascii_case_insensitive, overlapping)
344            .into()
345    }
346
347    #[cfg(feature = "find_many")]
348    fn str_find_many(
349        &self,
350        patterns: PyExpr,
351        ascii_case_insensitive: bool,
352        overlapping: bool,
353    ) -> Self {
354        self.inner
355            .clone()
356            .str()
357            .find_many(patterns.inner, ascii_case_insensitive, overlapping)
358            .into()
359    }
360
361    #[cfg(feature = "regex")]
362    fn str_escape_regex(&self) -> Self {
363        self.inner.clone().str().escape_regex().into()
364    }
365}