Permalink
Jan 14, 2015
Jan 14, 2015
Jan 1, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 1, 2015
Jan 1, 2015
Jan 1, 2015
Newer
100644
1801 lines (1569 sloc)
54.6 KB
9
__name__:'str',
10
$native:true
11
}
12
13
$StringDict.__add__ = function(self,other){
14
if(!(typeof other==="string")){
15
try{return getattr(other,'__radd__')(self)}
16
catch(err){throw _b_.TypeError(
17
"Can't convert "+$B.get_class(other).__name__+" to str implicitely")}
18
}
19
return self+other
20
}
21
22
$StringDict.__contains__ = function(self,item){
23
if(!(typeof item==="string")){throw _b_.TypeError(
24
"'in <string>' requires string as left operand, not "+item.__class__)}
25
var nbcar = item.length
26
if(nbcar==0) return true // a string contains the empty string
27
if(self.length==0) return nbcar==0
29
if(self.substr(i,nbcar)==item) return true
30
}
31
return false
32
}
33
34
$StringDict.__delitem__ = function(){
35
throw _b_.TypeError("'str' object doesn't support item deletion")
36
}
37
38
// __dir__must be assigned explicitely because attribute resolution for builtin
39
// classes doesn't use __mro__
40
$StringDict.__dir__ = $ObjectDict.__dir__
41
42
$StringDict.__eq__ = function(self,other){
43
if(other===undefined){ // compare object "self" to class "str"
44
return self===str
45
}
46
if (_b_.isinstance(other, _b_.str)) {
47
return other.valueOf() == self.valueOf()
48
}
49
return other===self.valueOf()
50
}
51
52
$StringDict.__format__ = function(self,arg){
53
var _fs = $FormattableString(self.valueOf())
57
return _fs.strformat(arg)
58
}
59
60
$StringDict.__getitem__ = function(self,arg){
61
if(isinstance(arg,_b_.int)){
62
var pos = arg
63
if(arg<0) pos+=self.length
64
if(pos>=0 && pos<self.length) return self.charAt(pos)
65
throw _b_.IndexError('string index out of range')
66
}
67
if(isinstance(arg,slice)) {
68
var step = arg.step===None ? 1 : arg.step
69
if(step>0){
70
var start = arg.start===None ? 0 : arg.start
71
var stop = arg.stop===None ? getattr(self,'__len__')() : arg.stop
72
}else{
73
var start = arg.start===None ? getattr(self,'__len__')()-1 : arg.start
74
var stop = arg.stop===None ? 0 : arg.stop
75
}
76
if(start<0) start+=self.length
77
if(stop<0) stop+=self.length
78
var res = '',i=null
79
if(step>0){
80
if(stop<=start) return ''
81
for(var i=start;i<stop;i+=step) res += self.charAt(i)
82
} else {
83
if(stop>=start) return ''
84
for(var i=start;i>=stop;i+=step) res += self.charAt(i)
85
}
86
return res
87
}
88
if(isinstance(arg,bool)) return self.__getitem__(_b_.int(arg))
89
}
90
91
// special method to speed up "for" loops
92
$StringDict.__getitems__ = function(self){return self.split('')}
93
94
$StringDict.__hash__ = function(self) {
95
if (self === undefined) {
96
return $StringDict.__hashvalue__ || $B.$py_next_hash-- // for hash of string type (not instance of string)
97
}
98
99
//http://stackoverflow.com/questions/2909106/python-whats-a-correct-and-good-way-to-implement-hash
100
// this implementation for strings maybe good enough for us..
101
102
var hash=1;
104
hash=(101*hash + self.charCodeAt(i)) & 0xFFFFFFFF
105
}
106
107
return hash
108
}
109
110
$StringDict.__init__ = function(self,arg){
111
self.valueOf = function(){return arg}
112
self.toString = function(){return arg}
113
}
114
115
var $str_iterator = $B.$iterator_class('str_iterator')
116
$StringDict.__iter__ = function(self){
117
var items = self.split('') // list of all characters in string
118
return $B.$iterator(items,$str_iterator)
119
}
120
121
$StringDict.__len__ = function(self){return self.length}
122
123
var kwarg_key = new RegExp('([^\\)]*)\\)')
124
125
var NotANumber = function() {
126
this.name = 'NotANumber'
127
}
128
129
var number_check=function(s) {
130
if(!isinstance(s,[_b_.int,_b_.float])){
131
throw new NotANumber()
132
}
133
}
134
135
var get_char_array = function(size, char) {
136
if (size <= 0)
137
return ''
138
return new Array(size + 1).join(char)
139
}
140
141
var format_padding = function(s, flags, minus_one) {
142
var padding = flags.padding
143
if (!padding) { // undefined
144
return s
145
}
146
s = s.toString()
147
padding = parseInt(padding, 10)
148
if (minus_one) { // numeric formatting where sign goes in front of padding
149
padding -= 1
150
}
151
if (!flags.left) {
152
return get_char_array(padding - s.length, flags.pad_char) + s
153
} else {
154
// left adjusted
155
return s + get_char_array(padding - s.length, flags.pad_char)
156
}
157
}
158
159
var format_int_precision = function(val, flags) {
160
var precision = flags.precision
161
if (!precision) {
162
return val.toString()
163
}
164
precision = parseInt(precision, 10)
165
var s = val.toString()
166
var sign = s[0]
167
if (s[0] === '-') {
168
return '-' + get_char_array(precision - s.length + 1, '0') + s.slice(1)
169
}
170
return get_char_array(precision - s.length, '0') + s
171
}
172
173
var format_float_precision = function(val, upper, flags, modifier) {
174
var precision = flags.precision
175
// val is a float
176
if (isFinite(val)) {
177
val = modifier(val, precision, flags, upper)
178
return val
179
}
180
if (val === Infinity) {
181
val = 'inf'
182
} else if (val === -Infinity) {
183
val = '-inf'
184
} else {
185
val = 'nan'
186
}
187
if (upper) {
188
return val.toUpperCase()
189
}
190
return val
192
}
193
194
var format_sign = function(val, flags) {
195
if (flags.sign) {
196
if (val >= 0) {
197
return "+"
199
} else if (flags.space) {
200
if (val >= 0) {
201
return " "
202
}
203
}
204
return ""
205
}
207
var str_format = function(val, flags) {
208
// string format supports left and right padding
209
flags.pad_char = " " // even if 0 padding is defined, don't use it
210
return format_padding(str(val), flags)
211
}
215
if (val.__class__ === $B.LongInt.$dict) {
216
val = $B.LongInt.$dict.to_base(val, 10)
217
} else {
218
val = parseInt(val)
219
}
220
221
var s = format_int_precision(val, flags)
222
if (flags.pad_char === '0') {
223
if (val < 0) {
224
s = s.substring(1)
225
return '-' + format_padding(s, flags, true)
226
}
227
var sign = format_sign(val, flags)
228
if (sign !== '') {
229
return sign + format_padding(s, flags, true)
230
}
231
}
232
233
return format_padding(format_sign(val, flags) + s, flags)
234
}
236
var repr_format = function(val, flags) {
237
flags.pad_char = " " // even if 0 padding is defined, don't use it
238
return format_padding(repr(val), flags)
239
}
241
var ascii_format = function(val, flags) {
242
flags.pad_char = " " // even if 0 padding is defined, don't use it
243
return format_padding(ascii(val), flags)
244
}
246
// converts to val to float and sets precision if missing
247
var _float_helper = function(val, flags) {
248
number_check(val)
249
if (!flags.precision) {
250
if (!flags.decimal_point) {
251
flags.precision = 6
252
} else {
253
flags.precision = 0
254
}
255
} else {
256
flags.precision = parseInt(flags.precision, 10)
257
validate_precision(flags.precision)
258
}
259
return parseFloat(val)
260
}
262
// used to capture and remove trailing zeroes
263
var trailing_zeros = /(.*?)(0+)([eE].*)/
264
var leading_zeros = /\.(0*)/
265
var trailing_dot = /\.$/
267
var validate_precision = function(precision) {
268
// force precision to limits of javascript
269
if (precision > 20) {
270
throw _b_.ValueError("precision too big")
271
}
272
}
273
274
// gG
275
var floating_point_format = function(val, upper, flags) {
276
val = _float_helper(val, flags)
277
var v = val.toString()
278
var v_len = v.length
279
var dot_idx = v.indexOf('.')
280
if (dot_idx < 0) {
281
dot_idx = v_len
282
}
283
if (val < 1 && val > -1) {
284
var zeros = leading_zeros.exec(v)
285
var numzeros
286
if (zeros) {
287
numzeros = zeros[1].length
288
} else {
289
numzeros = 0
290
}
291
if (numzeros >= 4) {
292
val = format_sign(val, flags) + format_float_precision(val, upper, flags, _floating_g_exp_helper)
293
if (!flags.alternate) {
294
var trl = trailing_zeros.exec(val)
295
if (trl) {
296
val = trl[1].replace(trailing_dot, '') + trl[3] // remove trailing
302
}
303
return format_padding(val, flags)
304
}
305
flags.precision += numzeros
306
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags,
307
function(val, precision) {
308
val = val.toFixed(min(precision, v_len - dot_idx) + numzeros)
309
}), flags)
310
}
311
312
if (dot_idx > flags.precision) {
313
val = format_sign(val, flags) + format_float_precision(val, upper, flags, _floating_g_exp_helper)
314
if (!flags.alternate) {
315
var trl = trailing_zeros.exec(val)
316
if (trl) {
317
val = trl[1].replace(trailing_dot, '') + trl[3] // remove trailing
318
}
319
} else {
320
if (flags.precision <= 1) {
321
val = val[0] + '.' + val.substring(1)
322
}
323
}
324
return format_padding(val, flags)
325
}
326
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags,
327
function(val, precision) {
328
if (!flags.decimal_point) {
329
precision = min(v_len - 1, 6)
330
} else if (precision > v_len) {
331
if (!flags.alternate) {
332
precision = v_len
334
}
335
if (precision < dot_idx) {
336
precision = dot_idx
337
}
338
return val.toFixed(precision - dot_idx)
339
}), flags)
340
}
342
var _floating_g_exp_helper = function(val, precision, flags, upper) {
343
if (precision) {
344
--precision
345
}
346
val = val.toExponential(precision)
347
// pad exponent to two digits
348
var e_idx = val.lastIndexOf('e')
349
if (e_idx > val.length - 4) {
350
val = val.substring(0, e_idx + 2) + '0' + val.substring(e_idx + 2)
351
}
352
if (upper) {
353
return val.toUpperCase()
354
}
355
return val
356
}
357
358
// fF
359
var floating_point_decimal_format = function(val, upper, flags) {
360
val = _float_helper(val, flags)
361
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags,
362
function(val, precision, flags) {
363
val = val.toFixed(precision)
364
if (precision === 0 && flags.alternate) {
365
val += '.'
366
}
367
return val
368
}), flags)
369
}
370
371
var _floating_exp_helper = function(val, precision, flags, upper) {
372
val = val.toExponential(precision)
373
// pad exponent to two digits
374
var e_idx = val.lastIndexOf('e')
375
if (e_idx > val.length - 4) {
376
val = val.substring(0, e_idx + 2) + '0' + val.substring(e_idx + 2)
377
}
378
if (upper) {
379
return val.toUpperCase()
380
}
381
return val
382
}
383
384
// eE
385
var floating_point_exponential_format = function(val, upper, flags) {
386
val = _float_helper(val, flags)
387
388
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags, _floating_exp_helper), flags)
389
}
390
391
var signed_hex_format = function(val, upper, flags) {
394
395
if (val.__class__ === $B.LongInt.$dict) {
396
ret=$B.LongInt.$dict.to_base(val, 16)
397
} else {
398
ret = parseInt(val)
399
ret = ret.toString(16)
400
}
401
ret = format_int_precision(ret, flags)
402
if (upper) {
403
ret = ret.toUpperCase()
404
}
405
if (flags.pad_char === '0') {
406
if (val < 0) {
407
ret = ret.substring(1)
408
ret = '-' + format_padding(ret, flags, true)
409
}
410
var sign = format_sign(val, flags)
411
if (sign !== '') {
412
ret = sign + format_padding(ret, flags, true)
414
}
415
416
if (flags.alternate) {
417
if (ret.charAt(0) === '-') {
418
if (upper) {
419
ret = "-0X" + ret.slice(1)
420
} else {
421
ret = "-0x" + ret.slice(1)
422
}
423
} else {
424
if (upper) {
425
ret = "0X" + ret
426
} else {
427
ret = "0x" + ret
428
}
429
}
430
}
431
return format_padding(format_sign(val, flags) + ret, flags)
432
}
434
var octal_format = function(val, flags) {
435
number_check(val)
436
var ret = parseInt(val)
437
ret = ret.toString(8)
438
ret = format_int_precision(ret, flags)
440
if (flags.pad_char === '0') {
441
if (val < 0) {
442
ret = ret.substring(1)
443
ret = '-' + format_padding(ret, flags, true)
444
}
445
var sign = format_sign(val, flags)
446
if (sign !== '') {
447
ret = sign + format_padding(ret, flags, true)
448
}
450
451
if (flags.alternate) {
452
if (ret.charAt(0) === '-') {
453
ret = "-0o" + ret.slice(1)
454
} else {
455
ret = "0o" + ret
456
}
458
return format_padding(ret, flags)
459
}
460
461
var single_char_format = function(val, flags) {
462
if(isinstance(val,str) && val.length==1) return val
463
try {
464
val = _b_.int(val) // yes, floats are valid (they are cast to int)
465
} catch (err) {
466
throw _b_.TypeError('%c requires int or char')
467
}
468
return format_padding(chr(val), flags)
469
}
470
471
var num_flag = function(c, flags) {
472
if (c === '0' && !flags.padding && !flags.decimal_point && !flags.left) {
473
flags.pad_char = '0'
474
return
475
}
476
if (!flags.decimal_point) {
477
flags.padding = (flags.padding || "") + c
478
} else {
479
flags.precision = (flags.precision || "") + c
480
}
481
}
482
483
var decimal_point_flag = function(val, flags) {
484
if (flags.decimal_point) {
485
// can only have one decimal point
486
throw new UnsupportedChar()
487
}
488
flags.decimal_point = true
489
}
490
491
var neg_flag = function(val, flags) {
492
flags.pad_char = ' ' // overrides '0' flag
493
flags.left = true
494
}
495
496
var space_flag = function(val, flags) {
497
flags.space = true
498
}
499
500
var sign_flag = function(val, flags) {
501
flags.sign = true
502
}
503
504
var alternate_flag = function(val, flags) {
505
flags.alternate = true
506
}
507
508
var char_to_func_mapping = {
509
's': str_format,
510
'd': num_format,
511
'i': num_format,
512
'u': num_format,
513
'o': octal_format,
514
'r': repr_format,
515
'a': ascii_format,
516
'g': function(val, flags) {return floating_point_format(val, false, flags)},
517
'G': function(val, flags) {return floating_point_format(val, true, flags)},
518
'f': function(val, flags) {return floating_point_decimal_format(val, false, flags)},
519
'F': function(val, flags) {return floating_point_decimal_format(val, true, flags)},
520
'e': function(val, flags) {return floating_point_exponential_format(val, false, flags)},
521
'E': function(val, flags) {return floating_point_exponential_format(val, true, flags)},
522
'x': function(val, flags) {return signed_hex_format(val, false, flags)},
523
'X': function(val, flags) {return signed_hex_format(val, true, flags)},
524
'c': single_char_format,
525
'0': function(val, flags) {return num_flag('0', flags)},
526
'1': function(val, flags) {return num_flag('1', flags)},
527
'2': function(val, flags) {return num_flag('2', flags)},
528
'3': function(val, flags) {return num_flag('3', flags)},
529
'4': function(val, flags) {return num_flag('4', flags)},
530
'5': function(val, flags) {return num_flag('5', flags)},
531
'6': function(val, flags) {return num_flag('6', flags)},
532
'7': function(val, flags) {return num_flag('7', flags)},
533
'8': function(val, flags) {return num_flag('8', flags)},
534
'9': function(val, flags) {return num_flag('9', flags)},
535
'-': neg_flag,
536
' ': space_flag,
537
'+': sign_flag,
538
'.': decimal_point_flag,
539
'#': alternate_flag
540
}
541
542
// exception thrown when an unsupported char is encountered in legacy format
543
var UnsupportedChar = function() {
544
this.name = "UnsupportedChar"
545
}
546
547
$StringDict.__mod__ = function(val, args) {
548
return $legacy_format(val, args, char_to_func_mapping)
549
}
550
551
var $legacy_format = function(val, args, char_mapping) {
552
var length = val.length
553
var pos = 0 |0
554
var argpos = null
556
argpos = 0 |0
557
}
558
var ret = ''
559
var $get_kwarg_string = function(s) {
560
// returns [val, newpos]
561
++pos
562
var rslt = kwarg_key.exec(s.substring(newpos))
563
if (!rslt) {
564
throw _b_.ValueError("incomplete format key")
565
}
566
var key = rslt[1]
567
newpos += rslt[0].length
568
try {
570
} catch(err) {
571
if (err.name === "KeyError") {
572
throw err
573
}
574
throw _b_.TypeError("format requires a mapping")
575
}
576
return get_string_value(s, val)
577
}
578
579
var $get_arg_string = function(s) {
580
// returns [val, newpos]
581
var val
582
583
// non-tuple args
584
if (argpos === null) {
585
// args is the value
586
val = args
587
} else {
588
try {
589
val = args[argpos++]
590
}
591
catch(err) {
592
if (err.name === "IndexError") {
593
throw _b_.TypeError("not enough arguments for format string")
594
} else {
595
throw err
596
}
599
return get_string_value(s, val)
600
}
601
var get_string_value = function(s, val) {
602
// todo: get flags, type
603
// todo: string value based on flags, type, value
604
var flags = {'pad_char': ' '}
605
do {
607
try {
608
if (func === undefined) {
609
throw new UnsupportedChar()
610
} else {
611
var ret = func(val, flags)
612
if (ret !== undefined) {
613
return ret
614
}
615
++newpos
616
}
617
} catch (err) {
618
if (err.name === "UnsupportedChar") {
619
invalid_char = s[newpos]
620
if (invalid_char === undefined) {
621
throw _b_.ValueError("incomplete format")
622
}
623
throw _b_.ValueError("unsupported format character '" + invalid_char +
624
"' (0x" + invalid_char.charCodeAt(0).toString(16) + ") at index " + newpos)
625
} else if (err.name === "NotANumber") {
626
var try_char = s[newpos]
627
var cls = val.__class__
628
if (!cls) {
629
if (typeof(val) === 'string') {
630
cls = 'str'
631
} else {
632
cls = typeof(val)
633
}
634
} else {
635
cls = cls.__name__
636
}
637
throw _b_.TypeError("%" + try_char + " format: a number is required, not " + cls)
638
} else {
639
throw err
640
}
646
if (newpos < 0) {
647
ret += val.substring(pos)
648
break
649
}
650
ret += val.substring(pos, newpos)
651
++newpos
652
if (newpos < length) {
653
if (val[newpos] === '%') {
654
ret += '%'
655
} else {
656
var tmp
657
if (val[newpos] === '(') {
658
++newpos
659
ret += $get_kwarg_string(val)
660
} else {
661
ret += $get_arg_string(val)
662
}
663
}
664
} else {
665
// % at end of string
666
throw _b_.ValueError("incomplete format")
667
}
668
pos = newpos + 1
669
} while (pos < length)
670
return ret
671
}
672
673
var char_to_new_format_mapping = {
674
'b': function(val, flags) {
675
number_check(val)
676
val = val.toString(2)
677
if (flags.alternate) {
678
val = "0b" + val
679
}
680
return val
681
},
682
'n': function(val, flags) {return floating_point_format(val, false, flags)},
683
'N': function(val, flags) {return floating_point_format(val, true, flags)}
684
}
686
for (k in char_to_func_mapping) {
687
char_to_new_format_mapping[k] = char_to_func_mapping[k]
688
}
689
690
$format_to_legacy = function(val, args) {
691
return $legacy_format(val, args, char_to_new_format_mapping)
692
}
693
694
$StringDict.__mro__ = [$StringDict,$ObjectDict]
695
696
$StringDict.__mul__ = function(self,other){
697
if(!isinstance(other,_b_.int)){throw _b_.TypeError(
698
"Can't multiply sequence by non-int of type '"+
699
$B.get_class(other).__name__+"'")}
700
$res = ''
701
for(var i=0;i<other;i++){$res+=self.valueOf()}
702
return $res
703
}
704
705
$StringDict.__ne__ = function(self,other){return other!==self.valueOf()}
706
707
$StringDict.__repr__ = function(self){
708
if(self.search('"')==-1 && self.search("'")==-1){
709
return "'"+self+"'"
710
}else if(self.search('"')==-1){
711
return '"'+self+'"'
712
}
713
var qesc = new RegExp("'","g") // to escape single quote
714
var res = self.replace(/\n/g,'\\\\n')
715
res = "'"+res.replace(qesc,"\\'")+"'"
716
return res
717
}
718
719
$StringDict.__setattr__ = function(self,attr,value){setattr(self,attr,value)}
720
721
$StringDict.__setitem__ = function(self,attr,value){
722
throw _b_.TypeError("'str' object does not support item assignment")
723
}
724
$StringDict.__str__ = function(self){
725
if(self===undefined) return "<class 'str'>"
726
return self.toString()
727
}
728
$StringDict.toString = function(){return 'string!'}
729
730
// generate comparison methods
731
var $comp_func = function(self,other){
732
if(typeof other !=="string"){throw _b_.TypeError(
733
"unorderable types: 'str' > "+$B.get_class(other).__name__+"()")}
734
return self > other
735
}
736
$comp_func += '' // source code
737
var $comps = {'>':'gt','>=':'ge','<':'lt','<=':'le'}
738
for(var $op in $comps){
739
eval("$StringDict.__"+$comps[$op]+'__ = '+$comp_func.replace(/>/gm,$op))
740
}
741
742
// add "reflected" methods
743
$B.make_rmethods($StringDict)
744
745
// unsupported operations
746
var $notimplemented = function(self,other){
747
throw NotImplementedError("OPERATOR not implemented for class str")
748
}
749
750
$StringDict.capitalize = function(self){
751
if(self.length==0) return ''
752
return self.charAt(0).toUpperCase()+self.substr(1).toLowerCase()
753
}
754
755
$StringDict.casefold = function(self) {
756
throw _b_.NotImplementedError("function casefold not implemented yet");
757
}
758
759
$StringDict.center = function(self,width,fillchar){
760
if(fillchar===undefined){fillchar=' '}else{fillchar=fillchar}
761
if(width<=self.length) return self
762
763
var pad = parseInt((width-self.length)/2)
764
var res = Array(pad+1).join(fillchar) // is this statement faster than the for loop below?
765
res += self + res
766
if(res.length<width){res += fillchar}
767
return res
768
}
769
770
$StringDict.count = function(self,elt){
771
if(!(typeof elt==="string")){throw _b_.TypeError(
772
"Can't convert '"+elt.__class__.__name__+"' object to str implicitly")}
773
//needs to be non overlapping occurrences of substring in string.
774
var n=0, pos=0
775
while(1){
776
pos=self.indexOf(elt,pos)
777
if(pos>=0){ n++; pos+=elt.length} else break;
778
}
779
return n
780
}
781
782
$StringDict.encode = function(self, encoding) {
783
if (encoding === undefined) encoding='utf-8'
784
if(encoding=='rot13' || encoding=='rot_13'){
785
// Special case : returns a string
786
var res = ''
787
for(var i=0, _len = self.length; i<_len ; i++){
788
var char = self.charAt(i)
789
if(('a'<=char && char<='m') || ('A'<=char && char<='M')){
790
res += String.fromCharCode(String.charCodeAt(char)+13)
791
}else if(('m'<char && char<='z') || ('M'<char && char<='Z')){
792
res += String.fromCharCode(String.charCodeAt(char)-13)
793
}else{res += char}
794
}
795
return res
796
}
798
}
799
800
$StringDict.endswith = function(self){
801
// Return True if the string ends with the specified suffix, otherwise
802
// return False. suffix can also be a tuple of suffixes to look for.
803
// With optional start, test beginning at that position. With optional
804
// end, stop comparing at that position.
805
var args = [], pos=0
806
for(var i=1, _len_i=arguments.length; i<_len_i;i++){args[pos++]=arguments[i]}
807
var start=null,end=null
808
var $ns=$B.$MakeArgs("$StringDict.endswith",args,['suffix'],
809
['start','end'],null,null)
810
var suffixes = $ns['suffix']
811
if(!isinstance(suffixes,_b_.tuple)){suffixes=[suffixes]}
812
start = $ns['start'] || start
813
end = $ns['end'] || self.length-1
814
var s = self.substr(start,end+1)
816
suffix = suffixes[i]
817
if(suffix.length<=s.length &&
818
s.substr(s.length-suffix.length)==suffix) return true
819
}
820
return false
821
}
822
823
$StringDict.expandtabs = function(self, tabsize) {
824
tabsize=tabsize || 8
825
var _str=''
826
for (var i=0; i < tabsize; i++) _str+=' '
827
return self.valueOf().replace(/\t/g, _str)
828
}
829
830
$StringDict.find = function(self){
831
// Return the lowest index in the string where substring sub is found,
832
// such that sub is contained in the slice s[start:end]. Optional
833
// arguments start and end are interpreted as in slice notation.
834
// Return -1 if sub is not found.
835
var start=0,end=self.length
836
var $ns=$B.$MakeArgs("$StringDict.find",arguments,['self','sub'],
837
['start','end'],null,null)
838
for(var attr in $ns){eval('var '+attr+'=$ns[attr]')}
839
if(!isinstance(sub,str)){throw _b_.TypeError(
840
"Can't convert '"+sub.__class__.__name__+"' object to str implicitly")}
841
if(!isinstance(start,_b_.int)||!isinstance(end,_b_.int)){
842
throw _b_.TypeError(
843
"slice indices must be integers or None or have an __index__ method")}
844
var s = self.substring(start,end)
845
var esc_sub = ''
847
switch(sub.charAt(i)) {
848
case '[':
849
case '.':
850
case '*':
851
case '+':
852
case '?':
853
case '|':
854
case '(':
855
case ')':
856
case '$':
857
case '^':
858
esc_sub += '\\'
859
}
860
esc_sub += sub.charAt(i)
861
}
862
var res = s.search(esc_sub)
863
if(res==-1) return -1
864
return start+res
865
}
866
867
var $FormattableString=function(format_string) {
868
// inspired from
869
// https://raw.github.com/florentx/stringformat/master/stringformat.py
870
this.format_string=format_string
871
872
this._prepare = function() {
873
//console.log('prepare')
874
var match = arguments[0]
875
//console.log('match1', match)
876
877
var p1 = '' + arguments[2]
878
879
if (match == '%') return '%%'
880
if (match.substring(0,1) == match.substring(match.length-1)) {
881
// '{{' or '}}'
882
return match.substring(0, Math.floor(match.length/2))
883
}
884
885
if (p1.charAt(0) == '{' && p1.charAt(match.length-1) == '}') {
886
p1=match.substring(1, p1.length-1)
887
}
888
889
var _repl
890
if (match.length >= 2) {
891
_repl=''
892
} else {
893
_repl = match.substring(1)
894
}
895
896
var _i = p1.indexOf(':')
897
var _out
898
if (_i > -1) {
899
_out = [p1.slice(0,_i), p1.slice(_i+1)]
900
} else { _out=[p1]}
901
902
var _field=_out[0] || ''
903
var _format_spec=_out[1] || ''
904
905
_out= _field.split('!')
906
var _literal=_out[0] || ''
907
var _sep=_field.indexOf('!') > -1?'!': undefined // _out[1]
908
var _conv=_out[1] //conversion
909
910
if (_sep && _conv === undefined) {
911
throw _b_.ValueError("end of format while looking for conversion specifier")
912
}
913
914
if (_conv !== undefined && _conv.length > 1) {
915
throw _b_.ValueError("expected ':' after format specifier")
916
}
917
918
if (_conv !== undefined && 'rsa'.indexOf(_conv) == -1) {
919
throw _b_.ValueError("Unknown conversion specifier " + _conv)
920
}
921
922
_name_parts=this.field_part.apply(null, [_literal])
923
924
var _start=_literal.charAt(0)
925
var _name=''
926
if (_start=='' || _start=='.' || _start == '[') {
927
// auto-numbering
928
if (this._index === undefined) {
929
throw _b_.ValueError("cannot switch from manual field specification to automatic field numbering")
930
}
931
932
_name = self._index.toString()
933
this._index+=1
934
935
if (! _literal ) {
936
_name_parts.shift()
937
}
938
} else {
939
_name = _name_parts.shift()[1]
941
// manual specification
942
if (this._index) {
943
throw _b_.ValueError("cannot switch from automatic field " +
944
"numbering to manual field specification")
945
this._index=undefined
946
}
947
}
948
}
949
950
var _empty_attribute=false
951
952
var _k
954
_k = _name_parts[i][0]
955
var _v = _name_parts[i][1]
956
var _tail = _name_parts[i][2]
957
if (_v === '') {_empty_attribute = true}
958
if (_tail !== '') {
959
throw _b_.ValueError("Only '.' or '[' may follow ']' " +
960
"in format field specifier")
961
}
962
}
963
964
if (_name_parts && _k == '[' && !
965
_literal.charAt(_literal.length) == ']') {
966
throw _b_.ValueError("Missing ']' in format string")
967
}
968
969
if (_empty_attribute) {
970
throw _b_.ValueError("Empty attribute in format string")
971
}
972
973
var _rv=''
974
if (_format_spec.indexOf('{') != -1) {
975
_format_spec = _format_spec.replace(this.format_sub_re, this._prepare)
976
_rv = [_name_parts, _conv, _format_spec]
977
if (this._nested[_name] === undefined) {
978
this._nested[_name]=[]
979
this._nested_array.push(_name)
980
}
981
this._nested[_name].push(_rv)
982
} else {
983
_rv = [_name_parts, _conv, _format_spec]
984
if (this._kwords[_name] === undefined) {
985
this._kwords[_name]=[]
986
this._kwords_array.push(_name)
987
}
988
this._kwords[_name].push(_rv)
989
}
990
991
return '%(' + id(_rv) + ')s'
992
} // this._prepare
993
994
this.format=function() {
995
// same as str.format() and unicode.format in Python 2.6+
996
997
var $ns=$B.$MakeArgs('format',arguments,[],[],'args','kwargs')
998
var args=$ns['args']
999
var kwargs=$ns['kwargs']
1000
1001
if (args.length>0) {
1003
//kwargs[str(i)]=args.$dict[i]
1004
getattr(kwargs, '__setitem__')(str(i), args[i])
1005
}
1006
}
1007
1008
//encode arguments to ASCII, if format string is bytes
1009
var _want_bytes = isinstance(this._string, str)
1010
var _params=_b_.dict()
1011
1013
var _name = this._kwords_array[i]
1014
var _items = this._kwords[_name]
1015
var _var = getattr(kwargs, '__getitem__')(_name)
1016
var _value;
1017
if (hasattr(_var, 'value')) {
1018
_value = getattr(_var, 'value')
1019
} else {
1020
_value=_var
1021
}
1022
1024
var _parts = _items[j][0]
1025
var _conv = _items[j][1]
1026
var _spec = _items[j][2]
1027
1028
var _f=this.format_field.apply(null, [_value, _parts,_conv,_spec,_want_bytes])
1029
getattr(_params,'__setitem__')(id(_items[j]).toString(), _f)
1030
}
1031
}
1032
1034
var _name = this._nested_array[i]
1035
var _items = this._nested[i]
1036
1037
var _var = getattr(kwargs, '__getitem__')(_name)
1038
var _value;
1039
if (hasattr(_var, 'value')) {
1040
_value = getattr(getattr(kwargs, '__getitem__')(_name), 'value')
1041
} else {
1042
_value=_var
1043
}
1044
1046
var _parts = _items[j][0]
1047
var _conv = _items[j][1]
1048
var _spec = _items[j][2]
1049
1051
1052
var _f=this.format_field.apply(null, [_value, _parts,_conv,_spec,_want_bytes])
1053
getattr(_params,'__setitem__')(id(_items[j]).toString(), _f)
1054
}
1055
}
1057
} // this.format
1058
1059
this.format_field=function(value,parts,conv,spec,want_bytes) {
1060
1061
if (want_bytes === undefined) want_bytes = false
1062
1064
var _k = parts[i][0]
1065
var _part = parts[i][1]
1066
1067
if (_k) {
1068
if (!isNaN(_part)) {
1069
value = value[parseInt(_part)]
1070
} else {
1071
value = getattr(value, _part)
1072
}
1073
} else {
1074
value = value[_part]
1075
}
1076
}
1077
1078
if (conv) {
1079
// fix me
1086
1087
return value
1088
}
1089
1090
this.strformat=function(value, format_spec) {
1091
if (format_spec === undefined) format_spec = ''
1092
if (!isinstance(value,[str,_b_.int]) && hasattr(value, '__format__')) {
1093
return getattr(value, '__format__')(format_spec)
1094
}
1095
var _m = this.format_spec_re.test(format_spec)
1096
1097
if (!_m) throw _b_.ValueError('Invalid conversion specification')
1098
1099
var _match=this.format_spec_re.exec(format_spec)
1100
var _align=_match[1]
1101
var _sign=_match[2]
1102
var _prefix=_match[3]
1103
var _width=_match[4]
1104
var _comma=_match[5]
1105
var _precision=_match[6]
1106
var _conversion=_match[7]
1107
1111
1112
if (_prefix != '' && ! _is_numeric) {
1113
if (_is_numeric) {
1114
throw _b_.ValueError('Alternate form (#) not allowed in float format specifier')
1115
} else {
1116
throw _b_.ValueError('Alternate form (#) not allowed in string format specification')
1117
}
1118
}
1119
1120
if (_is_numeric && _conversion == 'n') {
1121
_conversion = _is_integer && 'd' || 'g'
1122
} else {
1123
if (_sign) {
1124
if (! _is_numeric) {
1125
throw _b_.ValueError('Sign not allowed in string format specification');
1126
}
1127
if (_conversion == 'c') {
1128
throw("Sign not allowed with integer format specifier 'c'")
1129
}
1130
}
1131
}
1132
1133
if (_comma !== '') {
1134
value += ''
1135
var x = value.split('.')
1136
var x1 = x[0];
1137
var x2 = x.length > 1 ? '.' + x[1] : '';
1138
var rgx = /(\d+)(\d{3})/;
1139
1140
while (rgx.test(x1)) {
1141
x1 = x1.replace(rgx, '$1' + ',' + '$2');
1142
}
1143
value=x1+x2
1144
}
1145
1146
var _rv
1147
if (_conversion != '' && ((_is_numeric && _conversion == 's') ||
1148
(! _is_integer && 'coxX'.indexOf(_conversion) != -1))) {
1149
console.log(_conversion)
1150
throw _b_.ValueError('Fix me')
1151
}
1152
1153
if (_conversion == 'c') _conversion = 's'
1154
1155
// fix me
1156
_rv='%' + _prefix + _precision + (_conversion || 's')
1157
1159
1160
if (_sign != '-' && value >= 0) _rv = _sign + _rv
1161
1162
var _zero = false
1163
if (_width) {
1164
_zero = _width.charAt(0) == '0'
1165
_width = parseInt(_width)
1166
} else {
1167
_width = 0
1168
}
1169
1170
// Fastpath when alignment is not required
1171
1172
if (_width <= _rv.length) {
1174
throw _b_.ValueError("'=' alignment not allowed in string format specifier")
1175
}
1176
return _rv
1177
}
1178
1179
_fill = _align.substr(0,_align.length-1)
1180
_align= _align.substr(_align.length-1)
1181
1182
if (! _fill) {_fill = _zero && '0' || ' '}
1183
1184
if (_align == '^') {
1185
_rv = getattr(_rv, 'center')(_width, _fill)
1186
} else if (_align == '=' || (_zero && ! _align)) {
1187
if (! _is_numeric) {
1188
throw _b_.ValueError("'=' alignment not allowed in string format specifier")
1189
}
1190
if (_value < 0 || _sign != '-') {
1191
_rv = _rv.substring(0,1) + getattr(_rv.substring(1),'rjust')(_width - 1, _fill)
1192
} else {
1193
_rv = getattr(_rv, 'rjust')(_width, _fill)
1194
}
1195
} else if ((_align == '>' || _align == '=') || (_is_numeric && ! _aligned)) {
1196
_rv = getattr(_rv, 'rjust')(_width, _fill)
1197
} else if (_align == '<') {
1198
_rv = getattr(_rv, 'ljust')(_width, _fill)
1199
} else {
1200
throw _b_.ValueError("'" + _align + "' alignment not valid")
1201
}
1202
1203
return _rv
1204
}
1205
1206
this.field_part=function(literal) {
1207
if (literal.length == 0) return [['','','']]
1208
1209
var _matches=[]
1210
var _pos=0
1211
1212
var _start='', _middle='', _end=''
1213
var arg_name=''
1214
1215
// arg_name
1216
if (literal === undefined) console.log(literal)
1217
var _lit=literal.charAt(_pos)
1218
while (_pos < literal.length &&
1219
_lit !== '[' && _lit !== '.') {
1220
arg_name += _lit
1221
_pos++
1222
_lit=literal.charAt(_pos)
1223
}
1224
1225
// todo.. need to work on code below, but this takes cares of most
1226
// common cases.
1227
if (arg_name != '') _matches.push(['', arg_name, ''])
1228
1229
//return _matches
1230
1231
var attribute_name=''
1232
var element_index=''
1233
1234
//look for attribute_name and element_index
1235
while (_pos < literal.length) {
1236
var car = literal.charAt(_pos)
1237
1238
if (car == '[') { // element_index
1239
_start=_middle=_end=''
1240
_pos++
1241
1242
car = literal.charAt(_pos)
1243
while (_pos < literal.length && car !== ']') {
1244
_middle += car
1245
_pos++
1246
car = literal.charAt(_pos)
1247
}
1248
1249
_pos++
1250
if (car == ']') {
1251
while (_pos < literal.length) {
1252
_end+=literal.charAt(_pos)
1253
_pos++
1254
}
1255
}
1256
1257
_matches.push([_start, _middle, _end])
1258
1259
} else if (car == '.') { // attribute_name
1260
_middle=''
1261
_pos++
1262
car = literal.charAt(_pos)
1263
while (_pos < literal.length &&
1264
car !== '[' &&
1265
car !== '.') {
1266
//console.log(car)
1267
_middle += car
1268
_pos++
1269
car = literal.charAt(_pos)
1270
}
1271
1272
_matches.push(['.', _middle, ''])
1273
}
1274
}
1275
return _matches
1276
}
1277
1278
this.format_str_re = new RegExp(
1279
'(%)' +
1280
'|((?!{)(?:{{)+' +
1281
'|(?:}})+(?!})' +
1283
)
1284
1285
this.format_sub_re = new RegExp('({[^{}]*})') // nested replacement field
1286
1287
this.format_spec_re = new RegExp(
1288
'((?:[^{}]?[<>=^])?)' + // alignment
1289
'([\\-\\+ ]?)' + // sign
1290
'(#?)' + '(\\d*)' + '(,?)' + // base prefix, minimal width, thousands sep
1291
'((?:\.\\d+)?)' + // precision
1292
'(.?)$' // type
1293
)
1294
1295
this._index = 0
1296
this._kwords = {}
1297
this._kwords_array=[]
1298
this._nested = {}
1299
this._nested_array=[]
1300
1301
this._string=format_string.replace(this.format_str_re, this._prepare)
1302
1303
return this
1304
}
1305
1306
1307
$StringDict.format = function(self) {
1308
1309
var _fs = $FormattableString(self.valueOf())
1313
return _fs.format.apply(null, args)
1314
}
1315
1316
$StringDict.format_map = function(self) {
1317
throw NotImplementedError("function format_map not implemented yet");
1318
}
1319
1320
$StringDict.index = function(self){
1321
// Like find(), but raise ValueError when the substring is not found.
1322
var res = $StringDict.find.apply(self,arguments)
1323
if(res===-1) throw _b_.ValueError("substring not found")
1324
return res
1325
}
1326
1327
$StringDict.isalnum = function(self) {return /^[a-z0-9]+$/i.test(self)}
1328
1329
$StringDict.isalpha = function(self) {return /^[a-z]+$/i.test(self)}
1330
1331
$StringDict.isdecimal = function(self) {
1332
// this is not 100% correct
1333
return /^[0-9]+$/.test(self)
1334
}
1335
1336
$StringDict.isdigit = function(self) { return /^[0-9]+$/.test(self)}
1337
1338
$StringDict.isidentifier = function(self) {
1339
1340
switch(self) {
1341
case 'False':
1342
case 'None':
1343
case 'True':
1344
case 'and':
1345
case 'as':
1346
case 'assert':
1347
case 'break':
1348
case 'class':
1349
case 'continue':
1350
case 'def':
1351
case 'del':
1352
case 'elif':
1353
case 'else':
1354
case 'except':
1355
case 'finally':
1356
case 'for':
1357
case 'from':
1358
case 'global':
1359
case 'if':
1360
case 'import':
1361
case 'in':
1362
case 'is':
1363
case 'lambda':
1364
case 'nonlocal':
1365
case 'not':
1366
case 'or':
1367
case 'pass':
1368
case 'raise':
1369
case 'return':
1370
case 'try':
1371
case 'while':
1372
case 'with':
1373
case 'yield':
1374
return true
1375
}
1376
1377
// fixme.. this isn't complete but should be a good start
1378
return /^[a-z][0-9a-z_]+$/i.test(self)
1379
}
1380
1381
$StringDict.islower = function(self) {return /^[a-z]+$/.test(self)}
1382
1383
// not sure how to handle unicode variables
1384
$StringDict.isnumeric = function(self) {return /^[0-9]+$/.test(self)}
1385
1386
// inspired by http://www.codingforums.com/archive/index.php/t-17925.html
1387
$StringDict.isprintable = function(self) {return !/[^ -~]/.test(self)}
1388
1389
$StringDict.isspace = function(self) {return /^\s+$/i.test(self)}
1390
1391
$StringDict.istitle = function(self) {return /^([A-Z][a-z]+)(\s[A-Z][a-z]+)$/i.test(self)}
1392
1393
$StringDict.isupper = function(self) {return /^[A-Z]+$/.test(self)}
1394
1395
$StringDict.join = function(self,obj){
1396
var iterable=iter(obj)
1397
var res = '',count=0
1398
while(1){
1399
try{
1400
var obj2 = next(iterable)
1401
if(!isinstance(obj2,str)){throw _b_.TypeError(
1402
"sequence item "+count+": expected str instance, "+$B.get_class(obj2).__name__+" found")}
1403
res += obj2+self
1404
count++
1405
}catch(err){
1407
else{throw err}
1408
}
1409
}
1410
if(count==0) return ''
1411
return res.substr(0,res.length-self.length)
1412
}
1413
1414
$StringDict.ljust = function(self, width, fillchar) {
1415
if (width <= self.length) return self
1416
if (fillchar === undefined) fillchar=' '
1417
return self + Array(width - self.length + 1).join(fillchar)
1418
}
1419
1420
$StringDict.lower = function(self){return self.toLowerCase()}
1421
1422
$StringDict.lstrip = function(self,x){
1423
var pattern = null
1424
if(x==undefined){pattern="\\s*"}
1425
else{pattern = "["+x+"]*"}
1426
var sp = new RegExp("^"+pattern)
1427
return self.replace(sp,"")
1428
}
1429
1430
// note, maketrans should be a static function.
1431
$StringDict.maketrans = function(from, to) {
1432
var _t=[]
1433
// make 'default' translate table
1434
for(var i=0; i < 256; i++) _t[i]=String.fromCharCode(i)
1435
1436
// make substitution in the translation table
1438
var _ndx=from.source[i].charCodeAt(0) //retrieve ascii code of char
1439
_t[_ndx]=to.source[i]
1440
}
1441
1442
// create a data structure that string.translate understands
1446
}
1447
return _d
1448
}
1449
1450
$StringDict.partition = function(self,sep) {
1451
if (sep === undefined) {
1452
throw Error("sep argument is required");
1453
return
1454
}
1455
var i=self.indexOf(sep)
1456
if (i== -1) return _b_.tuple([self, '', ''])
1457
return _b_.tuple([self.substring(0,i), sep, self.substring(i+sep.length)])
1458
}
1459
1460
function $re_escape(str)
1461
{
1462
var specials = "[.*+?|()$^"
1464
var re = new RegExp('\\'+specials.charAt(i),'g')
1465
str = str.replace(re, "\\"+specials.charAt(i))
1466
}
1467
return str
1468
}
1469
1470
$StringDict.replace = function(self, old, _new, count) {
1471
// Replaces occurrences of 'old' by '_new'. Count references
1472
// the number of times to replace. In CPython, negative or undefined
1473
// values of count means replace all.
1474
if (count === undefined) {
1475
count = -1;
1476
} else {
1477
// Validate instance type of 'count'
1478
if (!isinstance(count,[_b_.int,_b_.float])) {
1479
throw _b_.TypeError("'" + str(count.__class__) + "' object cannot be interpreted as an integer");
1480
} else if (isinstance(count, _b_.float)) {
1481
throw _b_.TypeError("integer argument expected, got float");
1484
1485
var res = self.valueOf();
1486
var pos = -1;
1487
if (count < 0) count = res.length;
1488
while (count > 0) {
1489
pos = res.indexOf(old, pos);
1490
if (pos < 0)
1491
break;
1492
res = res.substr(0, pos) + _new + res.substr(pos + old.length);
1493
pos = pos + _new.length;
1494
count--;
1495
}
1496
return res;
1497
}
1498
1499
$StringDict.rfind = function(self){
1500
// Return the highest index in the string where substring sub is found,
1501
// such that sub is contained within s[start:end]. Optional arguments
1502
// start and end are interpreted as in slice notation. Return -1 on failure.
1503
var start=0,end=self.length
1504
var $ns=$B.$MakeArgs("$StringDict.find",arguments,['self','sub'],
1505
['start','end'],null,null)
1506
for(var attr in $ns){eval('var '+attr+'=$ns[attr]')}
1507
if(!isinstance(sub,str)){throw _b_.TypeError(
1508
"Can't convert '"+sub.__class__.__name__+"' object to str implicitly")}
1509
if(!isinstance(start,_b_.int)||!isinstance(end,_b_.int)){throw _b_.TypeError(
1510
"slice indices must be integers or None or have an __index__ method")}
1511
1512
var s = self.substring(start,end)
1513
//var reversed = '',rsub=''
1514
//for(var i=s.length-1;i>=0;i--){reversed += s.charAt(i)}
1515
//for(var i=sub.length-1;i>=0;i--){rsub += sub.charAt(i)}
1516
//var res = reversed.search($re_escape(rsub))
1517
//if(res==-1) return -1
1518
//return start+s.length-1-res-sub.length+1
1519
1520
// why not use lastIndexOf, which passes all brython tests..?
1521
return self.lastIndexOf(sub)
1522
}
1523
1524
$StringDict.rindex = function(){
1525
// Like rfind() but raises ValueError when the substring sub is not found
1526
var res = $StringDict.rfind.apply(this,arguments)
1527
if(res==-1){throw _b_.ValueError("substring not found")}
1528
return res
1529
}
1530
1531
$StringDict.rjust = function(self) {
1532
var fillchar = ' '
1533
var $ns=$B.$MakeArgs("$StringDict.rjust",arguments,['self','width'],
1534
['fillchar'],null,null)
1535
for(var attr in $ns){eval('var '+attr+'=$ns[attr]')}
1536
1537
if (width <= self.length) return self
1538
1539
return Array(width - self.length + 1).join(fillchar) + self
1540
}
1541
1542
$StringDict.rpartition = function(self,sep) {
1543
if (sep === undefined) {
1544
throw Error("sep argument is required");
1545
return
1546
}
1547
var pos=self.length-sep.length
1548
while(1){
1549
if(self.substr(pos,sep.length)==sep){
1550
return _b_.tuple([self.substr(0,pos),sep,self.substr(pos+sep.length)])
1551
}else{
1552
pos--
1553
if(pos<0){return _b_.tuple(['','',self])}
1554
}
1555
}
1556
}
1557
1558
$StringDict.rsplit = function(self) {
1559
var args = [], pos=0
1560
for(var i=1,_len_i=arguments.length;i<_len_i;i++){args[pos++]=arguments[i]}
1561
var $ns=$B.$MakeArgs("$StringDict.rsplit",args,[],[],'args','kw')
1562
var sep=None,maxsplit=-1
1563
if($ns['args'].length>=1){sep=$ns['args'][0]}
1564
if($ns['args'].length==2){maxsplit=$ns['args'][1]}
1571
if (array.length <= maxsplit || maxsplit == -1) return array
1572
1573
var s=[]
1574
1575
s = array.splice(array.length - maxsplit, array.length)
1576
s.splice(0, 0, array.join(sep))
1577
1578
return s
1579
}
1580
1581
$StringDict.rstrip = function(self,x){
1582
if(x==undefined){var pattern="\\s*"}
1583
else{var pattern = "["+x+"]*"}
1584
sp = new RegExp(pattern+'$')
1585
return str(self.replace(sp,""))
1586
}
1587
1588
$StringDict.split = function(self){
1589
var args = [], pos=0
1590
for(var i=1,_len_i=arguments.length;i<_len_i;i++){args[pos++]=arguments[i]}
1591
var $ns=$B.$MakeArgs("$StringDict.split",args,[],[],'args','kw')
1592
var sep=None,maxsplit=-1
1593
if($ns['args'].length>=1){sep=$ns['args'][0]}
1594
if($ns['args'].length==2){maxsplit=$ns['args'][1]}
1595
maxsplit = _b_.dict.$dict.get($ns['kw'],'maxsplit',maxsplit)
1597
if(sep===None){
1598
var res = []
1599
var pos = 0
1600
while(pos<self.length&&self.charAt(pos).search(/\s/)>-1){pos++}
1602
var name = ''
1603
while(1){
1604
if(self.charAt(pos).search(/\s/)===-1){
1605
if(name===''){name=self.charAt(pos)}
1606
else{name+=self.charAt(pos)}
1607
}else{
1608
if(name!==''){
1609
res.push(name)
1610
if(maxsplit!==-1&&res.length===maxsplit+1){
1611
res.pop()
1612
res.push(name+self.substr(pos))
1613
return res
1614
}
1615
name=''
1616
}
1617
}
1618
pos++
1619
if(pos>self.length-1){
1620
if(name){res.push(name)}
1621
break
1622
}
1623
}
1624
return res
1625
}else{
1626
var esc_sep = ''
1631
case '.':
1632
case '[':
1633
case ']':
1634
case '(':
1635
case ')':
1636
case '|':
1637
case '$':
1638
case '^':
1639
esc_sep += '\\'
1640
}
1641
esc_sep += sep.charAt(i)
1642
}
1643
var re = new RegExp(esc_sep)
1644
if (maxsplit==-1){
1645
// use native Javascript split on self
1646
return self.valueOf().split(re,maxsplit)
1647
}
1648
1649
// javascript split behavior is different from python when
1650
// a maxsplit argument is supplied. (see javascript string split
1651
// function docs for details)
1652
var l=self.valueOf().split(re,-1)
1655
if (b.length > 0) a.push(b.join(sep))
1656
1657
return a
1658
}
1659
}
1660
1661
$StringDict.splitlines = function(self){return $StringDict.split(self,'\n')}
1662
1663
$StringDict.startswith = function(self){
1664
// Return True if string starts with the prefix, otherwise return False.
1665
// prefix can also be a tuple of prefixes to look for. With optional
1666
// start, test string beginning at that position. With optional end,
1667
// stop comparing string at that position.
1668
var $ns=$B.$MakeArgs("$StringDict.startswith",arguments,['self','prefix'],
1669
['start','end'],null,null)
1670
var prefixes = $ns['prefix']
1671
if(!isinstance(prefixes,_b_.tuple)){prefixes=[prefixes]}
1672
var start = $ns['start'] || 0
1673
var end = $ns['end'] || self.length-1
1674
var s = self.substr(start,end+1)
1675
1677
if (s.indexOf(prefixes[i]) == 0) return true
1678
}
1679
return false
1680
}
1681
1682
$StringDict.strip = function(self,x){
1683
if(x==undefined){x = "\\s"}
1684
return $StringDict.rstrip($StringDict.lstrip(self,x),x)
1685
}
1686
1687
$StringDict.swapcase = function(self) {
1688
//inspired by http://www.geekpedia.com/code69_Swap-string-case-using-JavaScript.html
1689
return self.replace(/([a-z])|([A-Z])/g, function($0,$1,$2)
1690
{ return ($1) ? $0.toUpperCase() : $0.toLowerCase()
1691
})
1692
}
1693
1694
$StringDict.title = function(self) {
1695
//inspired from http://stackoverflow.com/questions/196972/convert-string-to-title-case-with-javascript
1696
return self.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
1697
}
1698
1699
$StringDict.translate = function(self,table) {
1704
if(repl==-1){res[pos++]=self.charAt(i)}
1705
else if(repl!==None){res[pos++]=repl}
1709
}
1710
1711
$StringDict.upper = function(self){return self.toUpperCase()}
1712
1713
$StringDict.zfill = function(self, width) {
1714
if (width === undefined || width <= self.length || !self.isnumeric()) {
1715
return self
1716
}
1717
1718
return Array(width - self.length +1).join('0');
1719
}
1720
1721
function str(arg){
1722
if(arg===undefined) return ''
1723
switch(typeof arg) {
1724
case 'string': return arg
1725
case 'number': return arg.toString()
1726
}
1732
// class or its subclasses, but the attribute __str__ of the
1733
// class metaclass (usually "type") or its subclasses (usually
1734
// "object")
1735
// The metaclass is the attribute __class__ of the class dictionary
1736
var func = $B.$type.__getattribute__(arg.$dict.__class__,'__str__')
1741
var f = getattr(arg,'__str__')
1742
// XXX fix : if not better than object.__str__, try __repr__
1743
return f()
1744
}
1745
catch(err){
1750
}catch(err){
1751
console.log(err+'\ndefault to toString '+arg);return arg.toString()
1752
}
1753
}
1754
}
1755
str.__class__ = $B.$factory
1756
str.$dict = $StringDict
1757
$StringDict.$factory = str
1758
$StringDict.__new__ = function(cls){
1759
if(cls===undefined){
1760
throw _b_.TypeError('str.__new__(): not enough arguments')
1761
}
1762
return {__class__:cls.$dict}
1763
}
1764
1767
// dictionary and factory for subclasses of string
1768
var $StringSubclassDict = {
1769
__class__:$B.$type,
1770
__name__:'str'
1771
}
1772
1773
// the methods in subclass apply the methods in $StringDict to the
1774
// result of instance.valueOf(), which is a Javascript string
1775
for(var $attr in $StringDict){
1776
if(typeof $StringDict[$attr]=='function'){
1777
$StringSubclassDict[$attr]=(function(attr){
1778
return function(){
1784
}
1785
}
1786
return $StringDict[attr].apply(null,args)
1787
}
1788
})($attr)
1789
}
1790
}
1791
$StringSubclassDict.__mro__ = [$StringSubclassDict,$ObjectDict]
1792
1793
// factory for str subclasses
1794
$B.$StringSubclassFactory = {
1795
__class__:$B.$factory,
1796
$dict:$StringSubclassDict
1797
}
1798
1799
_b_.str = str
1800
1801
})(__BRYTHON__)