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