1use polars::prelude::*;
2use pyo3::prelude::*;
3
4use crate::PyExpr;
5use crate::conversion::Wrap;
6use crate::error::PyPolarsErr;
7
8#[pymethods]
9impl PyExpr {
10 fn str_join(&self, delimiter: &str, ignore_nulls: bool) -> Self {
11 self.inner
12 .clone()
13 .str()
14 .join(delimiter, ignore_nulls)
15 .into()
16 }
17
18 #[pyo3(signature = (format, strict, exact, cache))]
19 fn str_to_date(&self, format: Option<String>, strict: bool, exact: bool, cache: bool) -> Self {
20 let format = format.map(|x| x.into());
21
22 let options = StrptimeOptions {
23 format,
24 strict,
25 exact,
26 cache,
27 };
28 self.inner.clone().str().to_date(options).into()
29 }
30
31 #[pyo3(signature = (format, time_unit, time_zone, strict, exact, cache, ambiguous))]
32 fn str_to_datetime(
33 &self,
34 format: Option<String>,
35 time_unit: Option<Wrap<TimeUnit>>,
36 time_zone: Wrap<Option<TimeZone>>,
37 strict: bool,
38 exact: bool,
39 cache: bool,
40 ambiguous: Self,
41 ) -> Self {
42 let format = format.map(|x| x.into());
43 let time_zone = time_zone.0;
44
45 let options = StrptimeOptions {
46 format,
47 strict,
48 exact,
49 cache,
50 };
51 self.inner
52 .clone()
53 .str()
54 .to_datetime(
55 time_unit.map(|tu| tu.0),
56 time_zone,
57 options,
58 ambiguous.inner,
59 )
60 .into()
61 }
62
63 #[pyo3(signature = (format, strict, cache))]
64 fn str_to_time(&self, format: Option<String>, strict: bool, cache: bool) -> Self {
65 let format = format.map(|x| x.into());
66
67 let options = StrptimeOptions {
68 format,
69 strict,
70 cache,
71 exact: true,
72 };
73 self.inner.clone().str().to_time(options).into()
74 }
75
76 fn str_strip_chars(&self, matches: Self) -> Self {
77 self.inner.clone().str().strip_chars(matches.inner).into()
78 }
79
80 fn str_strip_chars_start(&self, matches: Self) -> Self {
81 self.inner
82 .clone()
83 .str()
84 .strip_chars_start(matches.inner)
85 .into()
86 }
87
88 fn str_strip_chars_end(&self, matches: Self) -> Self {
89 self.inner
90 .clone()
91 .str()
92 .strip_chars_end(matches.inner)
93 .into()
94 }
95
96 fn str_strip_prefix(&self, prefix: Self) -> Self {
97 self.inner.clone().str().strip_prefix(prefix.inner).into()
98 }
99
100 fn str_strip_suffix(&self, suffix: Self) -> Self {
101 self.inner.clone().str().strip_suffix(suffix.inner).into()
102 }
103
104 fn str_slice(&self, offset: Self, length: Self) -> Self {
105 self.inner
106 .clone()
107 .str()
108 .slice(offset.inner, length.inner)
109 .into()
110 }
111
112 fn str_head(&self, n: Self) -> Self {
113 self.inner.clone().str().head(n.inner).into()
114 }
115
116 fn str_tail(&self, n: Self) -> Self {
117 self.inner.clone().str().tail(n.inner).into()
118 }
119
120 fn str_to_uppercase(&self) -> Self {
121 self.inner.clone().str().to_uppercase().into()
122 }
123
124 fn str_to_lowercase(&self) -> Self {
125 self.inner.clone().str().to_lowercase().into()
126 }
127
128 #[cfg(feature = "nightly")]
129 fn str_to_titlecase(&self) -> Self {
130 self.inner.clone().str().to_titlecase().into()
131 }
132
133 fn str_len_bytes(&self) -> Self {
134 self.inner.clone().str().len_bytes().into()
135 }
136
137 fn str_len_chars(&self) -> Self {
138 self.inner.clone().str().len_chars().into()
139 }
140
141 #[cfg(feature = "regex")]
142 fn str_replace_n(&self, pat: Self, val: Self, literal: bool, n: i64) -> Self {
143 self.inner
144 .clone()
145 .str()
146 .replace_n(pat.inner, val.inner, literal, n)
147 .into()
148 }
149
150 #[cfg(feature = "regex")]
151 fn str_replace_all(&self, pat: Self, val: Self, literal: bool) -> Self {
152 self.inner
153 .clone()
154 .str()
155 .replace_all(pat.inner, val.inner, literal)
156 .into()
157 }
158
159 fn str_normalize(&self, form: Wrap<UnicodeForm>) -> Self {
160 self.inner.clone().str().normalize(form.0).into()
161 }
162
163 fn str_reverse(&self) -> Self {
164 self.inner.clone().str().reverse().into()
165 }
166
167 fn str_pad_start(&self, length: usize, fill_char: char) -> Self {
168 self.inner.clone().str().pad_start(length, fill_char).into()
169 }
170
171 fn str_pad_end(&self, length: usize, fill_char: char) -> Self {
172 self.inner.clone().str().pad_end(length, fill_char).into()
173 }
174
175 fn str_zfill(&self, length: Self) -> Self {
176 self.inner.clone().str().zfill(length.inner).into()
177 }
178
179 #[pyo3(signature = (pat, literal, strict))]
180 #[cfg(feature = "regex")]
181 fn str_contains(&self, pat: Self, literal: Option<bool>, strict: bool) -> Self {
182 match literal {
183 Some(true) => self.inner.clone().str().contains_literal(pat.inner).into(),
184 _ => self.inner.clone().str().contains(pat.inner, strict).into(),
185 }
186 }
187
188 #[pyo3(signature = (pat, literal, strict))]
189 #[cfg(feature = "regex")]
190 fn str_find(&self, pat: Self, literal: Option<bool>, strict: bool) -> Self {
191 match literal {
192 Some(true) => self.inner.clone().str().find_literal(pat.inner).into(),
193 _ => self.inner.clone().str().find(pat.inner, strict).into(),
194 }
195 }
196
197 fn str_ends_with(&self, sub: Self) -> Self {
198 self.inner.clone().str().ends_with(sub.inner).into()
199 }
200
201 fn str_starts_with(&self, sub: Self) -> Self {
202 self.inner.clone().str().starts_with(sub.inner).into()
203 }
204
205 fn str_hex_encode(&self) -> Self {
206 self.inner.clone().str().hex_encode().into()
207 }
208
209 #[cfg(feature = "binary_encoding")]
210 fn str_hex_decode(&self, strict: bool) -> Self {
211 self.inner.clone().str().hex_decode(strict).into()
212 }
213
214 fn str_base64_encode(&self) -> Self {
215 self.inner.clone().str().base64_encode().into()
216 }
217
218 #[cfg(feature = "binary_encoding")]
219 fn str_base64_decode(&self, strict: bool) -> Self {
220 self.inner.clone().str().base64_decode(strict).into()
221 }
222
223 fn str_to_integer(&self, base: Self, strict: bool) -> Self {
224 self.inner
225 .clone()
226 .str()
227 .to_integer(base.inner, strict)
228 .with_fmt("str.to_integer")
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<Wrap<DataType>>,
237 infer_schema_len: Option<usize>,
238 ) -> Self {
239 let dtype = dtype.map(|wrap| wrap.0);
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}