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