@@ -7,6 +7,7 @@ use super::objsequence::PySliceableSequence;
7
7
use super :: objtype;
8
8
use num_bigint:: ToBigInt ;
9
9
use num_traits:: ToPrimitive ;
10
+ use std:: fmt;
10
11
use std:: hash:: { Hash , Hasher } ;
11
12
12
13
pub fn init ( context : & PyContext ) {
@@ -43,6 +44,14 @@ pub fn init(context: &PyContext) {
43
44
"startswith" ,
44
45
context. new_rustfunc ( str_startswith) ,
45
46
) ;
47
+ context. set_attr ( & str_type, "isalnum" , context. new_rustfunc ( str_isalnum) ) ;
48
+ context. set_attr ( & str_type, "isnumeric" , context. new_rustfunc ( str_isnumeric) ) ;
49
+ context. set_attr ( & str_type, "isdigit" , context. new_rustfunc ( str_isdigit) ) ;
50
+ context. set_attr ( & str_type, "title" , context. new_rustfunc ( str_title) ) ;
51
+ context. set_attr ( & str_type, "swapcase" , context. new_rustfunc ( str_swapcase) ) ;
52
+ context. set_attr ( & str_type, "isalpha" , context. new_rustfunc ( str_isalpha) ) ;
53
+ context. set_attr ( & str_type, "replace" , context. new_rustfunc ( str_replace) ) ;
54
+ context. set_attr ( & str_type, "center" , context. new_rustfunc ( str_center) ) ;
46
55
}
47
56
48
57
pub fn get_value ( obj : & PyObjectRef ) -> String {
@@ -238,6 +247,82 @@ fn str_endswith(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
238
247
Ok ( vm. ctx . new_bool ( value. ends_with ( pat. as_str ( ) ) ) )
239
248
}
240
249
250
+ fn str_swapcase ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
251
+ arg_check ! ( vm, args, required = [ ( s, Some ( vm. ctx. str_type( ) ) ) ] ) ;
252
+ let value = get_value ( & s) ;
253
+ let mut swapped_str = String :: with_capacity ( value. len ( ) ) ;
254
+ for c in value. chars ( ) {
255
+ // to_uppercase returns an iterator, to_ascii_uppercase returns the char
256
+ if c. is_lowercase ( ) {
257
+ swapped_str. push ( c. to_ascii_uppercase ( ) ) ;
258
+ } else if c. is_uppercase ( ) {
259
+ swapped_str. push ( c. to_ascii_lowercase ( ) ) ;
260
+ } else {
261
+ swapped_str. push ( c) ;
262
+ }
263
+ }
264
+ Ok ( vm. ctx . new_str ( swapped_str) )
265
+ }
266
+
267
+ fn str_replace ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
268
+ arg_check ! (
269
+ vm,
270
+ args,
271
+ required = [
272
+ ( s, Some ( vm. ctx. str_type( ) ) ) ,
273
+ ( old, Some ( vm. ctx. str_type( ) ) ) ,
274
+ ( rep, Some ( vm. ctx. str_type( ) ) )
275
+ ] ,
276
+ optional = [ ( n, None ) ]
277
+ ) ;
278
+ let s = get_value ( & s) ;
279
+ let old_str = get_value ( & old) ;
280
+ let rep_str = get_value ( & rep) ;
281
+ let num_rep: usize = match n {
282
+ Some ( num) => objint:: to_int ( vm, num, 10 ) ?. to_usize ( ) . unwrap ( ) ,
283
+ None => 1 ,
284
+ } ;
285
+ let new_str = s. replacen ( & old_str, & rep_str, num_rep) ;
286
+ Ok ( vm. ctx . new_str ( new_str) )
287
+ }
288
+
289
+ fn str_title ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
290
+ arg_check ! ( vm, args, required = [ ( s, Some ( vm. ctx. str_type( ) ) ) ] ) ;
291
+ let value = get_value ( & s) ;
292
+ let titled_str = value
293
+ . split ( ' ' )
294
+ . map ( |w| {
295
+ let mut c = w. chars ( ) ;
296
+ match c. next ( ) {
297
+ None => String :: new ( ) ,
298
+ Some ( f) => f
299
+ . to_uppercase ( )
300
+ . chain ( c. flat_map ( |t| t. to_lowercase ( ) ) )
301
+ . collect ( ) ,
302
+ }
303
+ } )
304
+ . collect :: < Vec < _ > > ( )
305
+ . join ( " " ) ;
306
+ Ok ( vm. ctx . new_str ( titled_str) )
307
+ }
308
+
309
+ // TODO: add ability to specify fill character, can't pass it to format!()
310
+ fn str_center ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
311
+ arg_check ! (
312
+ vm,
313
+ args,
314
+ required = [ ( s, Some ( vm. ctx. str_type( ) ) ) , ( len, Some ( vm. ctx. int_type( ) ) ) ] // optional = [(chars, None)]
315
+ ) ;
316
+ let value = get_value ( & s) ;
317
+ let len = objint:: get_value ( & len) . to_usize ( ) . unwrap ( ) ;
318
+ // let rep_char = match chars {
319
+ // Some(c) => get_value(&c),
320
+ // None => " ".to_string(),
321
+ // };
322
+ let new_str = format ! ( "{:^1$}" , value, len) ;
323
+ Ok ( vm. ctx . new_str ( new_str) )
324
+ }
325
+
241
326
fn str_startswith ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
242
327
arg_check ! (
243
328
vm,
@@ -263,6 +348,47 @@ fn str_contains(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
263
348
Ok ( vm. ctx . new_bool ( value. contains ( needle. as_str ( ) ) ) )
264
349
}
265
350
351
+ fn str_isalnum ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
352
+ arg_check ! ( vm, args, required = [ ( s, Some ( vm. ctx. str_type( ) ) ) ] ) ;
353
+ let is_alnum = get_value ( & s) . chars ( ) . all ( |c| c. is_alphanumeric ( ) ) ;
354
+ Ok ( vm. ctx . new_bool ( is_alnum) )
355
+ }
356
+
357
+ fn str_isnumeric ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
358
+ arg_check ! ( vm, args, required = [ ( s, Some ( vm. ctx. str_type( ) ) ) ] ) ;
359
+ let is_numeric = get_value ( & s) . chars ( ) . all ( |c| c. is_numeric ( ) ) ;
360
+ Ok ( vm. ctx . new_bool ( is_numeric) )
361
+ }
362
+
363
+ fn str_isalpha ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
364
+ arg_check ! ( vm, args, required = [ ( s, Some ( vm. ctx. str_type( ) ) ) ] ) ;
365
+ let is_alpha = get_value ( & s) . chars ( ) . all ( |c| c. is_alphanumeric ( ) ) ;
366
+ Ok ( vm. ctx . new_bool ( is_alpha) )
367
+ }
368
+
369
+ fn str_isdigit ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
370
+ arg_check ! ( vm, args, required = [ ( s, Some ( vm. ctx. str_type( ) ) ) ] ) ;
371
+ let value = get_value ( & s) ;
372
+ // python's isdigit also checks if exponents are digits, these are the unicodes for exponents
373
+ let valid_unicodes: [ u16 ; 10 ] = [
374
+ 0x2070 , 0x00B9 , 0x00B2 , 0x00B3 , 0x2074 , 0x2075 , 0x2076 , 0x2077 , 0x2078 , 0x2079 ,
375
+ ] ;
376
+ let mut is_digit: bool = true ;
377
+ for c in value. chars ( ) {
378
+ if !c. is_digit ( 10 ) {
379
+ // checking if char is exponent
380
+ let char_as_uni: u16 = c as u16 ;
381
+ if valid_unicodes. contains ( & char_as_uni) {
382
+ continue ;
383
+ } else {
384
+ is_digit = false ;
385
+ break ;
386
+ }
387
+ }
388
+ }
389
+ Ok ( vm. ctx . new_bool ( is_digit) )
390
+ }
391
+
266
392
fn str_getitem ( vm : & mut VirtualMachine , args : PyFuncArgs ) -> PyResult {
267
393
arg_check ! (
268
394
vm,
0 commit comments