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: PyExpr, fill_char: char) -> Self {
169        self.inner
170            .clone()
171            .str()
172            .pad_start(length.inner, fill_char)
173            .into()
174    }
175
176    fn str_pad_end(&self, length: PyExpr, fill_char: char) -> Self {
177        self.inner
178            .clone()
179            .str()
180            .pad_end(length.inner, fill_char)
181            .into()
182    }
183
184    fn str_zfill(&self, length: PyExpr) -> Self {
185        self.inner.clone().str().zfill(length.inner).into()
186    }
187
188    #[pyo3(signature = (pat, literal, strict))]
189    #[cfg(feature = "regex")]
190    fn str_contains(&self, pat: Self, literal: Option<bool>, strict: bool) -> Self {
191        match literal {
192            Some(true) => self.inner.clone().str().contains_literal(pat.inner).into(),
193            _ => self.inner.clone().str().contains(pat.inner, strict).into(),
194        }
195    }
196
197    #[pyo3(signature = (pat, literal, strict))]
198    #[cfg(feature = "regex")]
199    fn str_find(&self, pat: Self, literal: Option<bool>, strict: bool) -> Self {
200        match literal {
201            Some(true) => self.inner.clone().str().find_literal(pat.inner).into(),
202            _ => self.inner.clone().str().find(pat.inner, strict).into(),
203        }
204    }
205
206    fn str_ends_with(&self, sub: Self) -> Self {
207        self.inner.clone().str().ends_with(sub.inner).into()
208    }
209
210    fn str_starts_with(&self, sub: Self) -> Self {
211        self.inner.clone().str().starts_with(sub.inner).into()
212    }
213
214    fn str_hex_encode(&self) -> Self {
215        self.inner.clone().str().hex_encode().into()
216    }
217
218    #[cfg(feature = "binary_encoding")]
219    fn str_hex_decode(&self, strict: bool) -> Self {
220        self.inner.clone().str().hex_decode(strict).into()
221    }
222
223    fn str_base64_encode(&self) -> Self {
224        self.inner.clone().str().base64_encode().into()
225    }
226
227    #[cfg(feature = "binary_encoding")]
228    fn str_base64_decode(&self, strict: bool) -> Self {
229        self.inner.clone().str().base64_decode(strict).into()
230    }
231
232    #[pyo3(signature = (base, dtype=Some(Wrap(DataType::Int64)), strict=true))]
233    fn str_to_integer(&self, base: Self, dtype: Option<Wrap<DataType>>, strict: bool) -> Self {
234        self.inner
235            .clone()
236            .str()
237            .to_integer(base.inner, dtype.map(|wrap| wrap.0), strict)
238            .into()
239    }
240
241    #[cfg(feature = "extract_jsonpath")]
242    #[pyo3(signature = (dtype=None, infer_schema_len=None))]
243    fn str_json_decode(
244        &self,
245        dtype: Option<PyDataTypeExpr>,
246        infer_schema_len: Option<usize>,
247    ) -> Self {
248        let dtype = dtype.map(|wrap| wrap.inner);
249        self.inner
250            .clone()
251            .str()
252            .json_decode(dtype, infer_schema_len)
253            .into()
254    }
255
256    #[cfg(feature = "extract_jsonpath")]
257    fn str_json_path_match(&self, pat: Self) -> Self {
258        self.inner.clone().str().json_path_match(pat.inner).into()
259    }
260
261    fn str_extract(&self, pat: Self, group_index: usize) -> Self {
262        self.inner
263            .clone()
264            .str()
265            .extract(pat.inner, group_index)
266            .into()
267    }
268
269    fn str_extract_all(&self, pat: Self) -> Self {
270        self.inner.clone().str().extract_all(pat.inner).into()
271    }
272
273    #[cfg(feature = "extract_groups")]
274    fn str_extract_groups(&self, pat: &str) -> PyResult<Self> {
275        Ok(self
276            .inner
277            .clone()
278            .str()
279            .extract_groups(pat)
280            .map_err(PyPolarsErr::from)?
281            .into())
282    }
283
284    fn str_count_matches(&self, pat: Self, literal: bool) -> Self {
285        self.inner
286            .clone()
287            .str()
288            .count_matches(pat.inner, literal)
289            .into()
290    }
291
292    fn str_split(&self, by: Self) -> Self {
293        self.inner.clone().str().split(by.inner).into()
294    }
295
296    fn str_split_inclusive(&self, by: Self) -> Self {
297        self.inner.clone().str().split_inclusive(by.inner).into()
298    }
299
300    fn str_split_exact(&self, by: Self, n: usize) -> Self {
301        self.inner.clone().str().split_exact(by.inner, n).into()
302    }
303
304    fn str_split_exact_inclusive(&self, by: Self, n: usize) -> Self {
305        self.inner
306            .clone()
307            .str()
308            .split_exact_inclusive(by.inner, n)
309            .into()
310    }
311
312    fn str_splitn(&self, by: Self, n: usize) -> Self {
313        self.inner.clone().str().splitn(by.inner, n).into()
314    }
315
316    fn str_to_decimal(&self, infer_len: usize) -> Self {
317        self.inner.clone().str().to_decimal(infer_len).into()
318    }
319
320    #[cfg(feature = "find_many")]
321    fn str_contains_any(&self, patterns: PyExpr, ascii_case_insensitive: bool) -> Self {
322        self.inner
323            .clone()
324            .str()
325            .contains_any(patterns.inner, ascii_case_insensitive)
326            .into()
327    }
328    #[cfg(feature = "find_many")]
329    fn str_replace_many(
330        &self,
331        patterns: PyExpr,
332        replace_with: PyExpr,
333        ascii_case_insensitive: bool,
334    ) -> Self {
335        self.inner
336            .clone()
337            .str()
338            .replace_many(patterns.inner, replace_with.inner, ascii_case_insensitive)
339            .into()
340    }
341
342    #[cfg(feature = "find_many")]
343    fn str_extract_many(
344        &self,
345        patterns: PyExpr,
346        ascii_case_insensitive: bool,
347        overlapping: bool,
348    ) -> Self {
349        self.inner
350            .clone()
351            .str()
352            .extract_many(patterns.inner, ascii_case_insensitive, overlapping)
353            .into()
354    }
355
356    #[cfg(feature = "find_many")]
357    fn str_find_many(
358        &self,
359        patterns: PyExpr,
360        ascii_case_insensitive: bool,
361        overlapping: bool,
362    ) -> Self {
363        self.inner
364            .clone()
365            .str()
366            .find_many(patterns.inner, ascii_case_insensitive, overlapping)
367            .into()
368    }
369
370    #[cfg(feature = "regex")]
371    fn str_escape_regex(&self) -> Self {
372        self.inner.clone().str().escape_regex().into()
373    }
374}