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