Skip to content
Permalink
Newer
Older
100644 1881 lines (1646 sloc) 57.3 KB
Sep 5, 2014
1
;(function($B){
2
3
eval($B.InjectBuiltins())
Sep 5, 2014
4
5
var $ObjectDict = object.$dict
6
7
var $StringDict = {__class__:$B.$type,
8
__dir__:$ObjectDict.__dir__,
Sep 5, 2014
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
28
for(var i=0, _len_i = self.length; i < _len_i;i++){
Sep 5, 2014
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
Sep 5, 2014
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
}
Sep 5, 2014
49
return other===self.valueOf()
50
}
51
52
$StringDict.__format__ = function(self,arg){
53
var _fs = $FormattableString(self.valueOf())
54
var args=[], pos=0
Sep 5, 2014
55
// we don't need the first item (ie, self)
56
for (var i=1,_len_i=arguments.length;i<_len_i;i++){args[pos++]=arguments[i]}
Sep 5, 2014
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
Sep 5, 2014
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;
100
for(var i=0, _len_i = self.length; i < _len_i; i++) {
Sep 5, 2014
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
Sep 5, 2014
193
194
}
195
196
var format_sign = function(val, flags) {
197
if (flags.sign) {
198
if (val >= 0) {
199
return "+"
Sep 5, 2014
200
}
201
} else if (flags.space) {
202
if (val >= 0) {
203
return " "
204
}
205
}
206
return ""
207
}
Sep 5, 2014
208
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
}
Sep 5, 2014
214
215
var num_format = function(val, flags) {
216
number_check(val)
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
}
Sep 5, 2014
237
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
}
Sep 5, 2014
242
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
}
Sep 5, 2014
247
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
}
Sep 5, 2014
263
264
// used to capture and remove trailing zeroes
265
var trailing_zeros = /(.*?)(0+)([eE].*)/
266
var leading_zeros = /\.(0*)/
267
var trailing_dot = /\.$/
Sep 5, 2014
268
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
300
} else {
301
if (flags.precision <= 1) {
302
val = val[0] + '.' + val.substring(1)
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
Sep 5, 2014
335
}
336
}
337
if (precision < dot_idx) {
338
precision = dot_idx
339
}
340
return val.toFixed(precision - dot_idx)
341
}), flags)
342
}
Sep 5, 2014
343
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) {
395
number_check(val)
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)
Sep 5, 2014
415
}
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
}
Sep 5, 2014
435
436
var octal_format = function(val, flags) {
437
number_check(val)
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
447
ret = format_int_precision(ret, flags)
Sep 5, 2014
448
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
}
Sep 5, 2014
458
}
459
460
if (flags.alternate) {
461
if (ret.charAt(0) === '-') {
462
ret = "-0o" + ret.slice(1)
463
} else {
464
ret = "0o" + ret
465
}
Sep 5, 2014
466
}
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
564
if (args && _b_.isinstance(args, _b_.tuple)) {
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 {
578
var val = _b_.getattr(args.__class__,'__getitem__')(args, key)
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
}
Sep 5, 2014
606
}
607
}
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 {
615
var func = char_mapping[s[newpos]]
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
}
Sep 5, 2014
650
}
651
} while (true)
Sep 5, 2014
652
}
654
var newpos = val.indexOf('%', pos)
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
}
Sep 5, 2014
694
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
}
Sep 5, 2014
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){
May 19, 2015
717
if(self.search('"')==-1 && self.search("'")==-1){
718
return "'"+self+"'"
719
}else if(self.search('"')==-1){
720
return '"'+self+'"'
721
}
Sep 5, 2014
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
}
806
return _b_.bytes(self, encoding)
Sep 5, 2014
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)
Sep 5, 2014
818
var suffixes = $ns['suffix']
819
if(!isinstance(suffixes,_b_.tuple)){suffixes=[suffixes]}
820
var start = $ns['start'],
821
end = $ns['end']
Sep 5, 2014
822
var s = self.substr(start,end+1)
823
for(var i=0, _len_i = suffixes.length; i < _len_i;i++){
Sep 5, 2014
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)
Sep 5, 2014
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 = ''
856
for(var i=0, _len_i = sub.length; i < _len_i;i++){
Sep 5, 2014
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
942
_name = this._index.toString()
Sep 5, 2014
943
this._index+=1
944
945
if (! _literal ) {
946
_name_parts.shift()
947
}
948
} else {
949
_name = _name_parts.shift()[1]
950
if (this._index !== undefined && !isNaN(_name)) {
Sep 5, 2014
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
963
for (var i=0, _len_i = _name_parts.length; i < _len_i; i++) {
Sep 5, 2014
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
1007
var $ns=$B.$MakeArgs1('format',0,{},[],arguments,{},'args','kwargs')
Sep 5, 2014
1008
var args=$ns['args']
1009
var kwargs=$ns['kwargs']
1010
1011
if (args.length>0) {
1012
for (var i=0, _len_i = args.length; i < _len_i; i++) {
Sep 5, 2014
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
1022
for (var i=0, _len_i = this._kwords_array.length; i < _len_i; i++) {
Sep 5, 2014
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
1033
for (var j=0, _len_j = _items.length; j < _len_j; j++) {
Sep 5, 2014
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
1043
for (var i=0, _len_i = this._nested_array.length; i < _len_i; i++) {
Sep 5, 2014
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
1055
for (var j=0, _len_j = _items.length; j < _len_j; j++) {
Sep 5, 2014
1056
var _parts = _items[j][0]
1057
var _conv = _items[j][1]
1058
var _spec = _items[j][2]
1059
1060
_spec=$format_to_legacy(_spec, _params)
Sep 5, 2014
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
}
1066
return $format_to_legacy(this._string, _params)
Sep 5, 2014
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
1073
for (var i=0, _len_i = parts.length; i < _len_i; i++) {
Sep 5, 2014
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
1090
value = $format_to_legacy((conv == 'r') && '%r' || '%s', value)
Sep 5, 2014
1091
}
1092
1093
value = this.strformat(value, spec)
1094
1095
if (want_bytes) { return value.toString()}
Sep 5, 2014
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
1118
var _is_float = isinstance(value, _b_.float)
Sep 5, 2014
1119
var _is_integer = isinstance(value, _b_.int)
1120
var _is_numeric = _is_float || _is_integer
Sep 5, 2014
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
1168
_rv = $format_to_legacy(_rv, value)
Sep 5, 2014
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) {
1183
if (! _is_float && (_align == '=' || (_zero && ! _align))) {
Sep 5, 2014
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
'|(?:}})+(?!})' +
1292
'|{(?:[^{}](?:[^{}]+|{[^{}]*})*)?})', 'g'
Sep 5, 2014
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())
1320
var args=[], pos=0
Sep 5, 2014
1321
// we don't need the first item (ie, self)
1322
for (var i=1,_len_i=arguments.length;i<_len_i;i++){args[pos++]=arguments[i]}
Sep 5, 2014
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){
1416
if(err.__name__==='StopIteration'){break}
Sep 5, 2014
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
1447
for(var i=0, _len_i = from.source.length; i < _len_i; i++) {
Sep 5, 2014
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
1453
var _d=dict()
Sep 5, 2014
1454
for(var i=0; i < 256; i++) {
1455
_b_.dict.$dict.__setitem__(_d, i, _t[i])
Sep 5, 2014
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 = "[.*+?|()$^"
1473
for(var i=0, _len_i = specials.length; i < _len_i;i++){
Sep 5, 2014
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");
Sep 5, 2014
1492
}
1493
}
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;
Sep 5, 2014
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)
Sep 5, 2014
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)
Sep 5, 2014
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)
Sep 5, 2014
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]}
1567
var $ns=$B.$MakeArgs1("$StringDict.rsplit",0,{},[],args,{},'args','kw')
Sep 5, 2014
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]}
1571
maxsplit = _b_.dict.$dict.get($ns['kw'],'maxsplit',maxsplit)
Sep 5, 2014
1572
1573
//var array=$StringDict.split(self)
Sep 5, 2014
1574
1575
var array=$StringDict.split(self, sep)
Sep 5, 2014
1576
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
Sep 5, 2014
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]}
1597
var $ns=$B.$MakeArgs1("$StringDict.split",0,{},[],args,{},'args','kw')
Sep 5, 2014
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)
1602
if(sep=='') throw _b_.ValueError('empty separator')
Sep 5, 2014
1603
if(sep===None){
1604
var res = []
1605
var pos = 0
1606
while(pos<self.length&&self.charAt(pos).search(/\s/)>-1){pos++}
1607
if(pos===self.length-1){return [self]}
Sep 5, 2014
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 = ''
1633
for(var i=0, _len_i = sep.length; i < _len_i;i++){
Sep 5, 2014
1634
switch(sep.charAt(i)) {
1635
case '*':
Feb 9, 2015
1636
case '+':
Sep 5, 2014
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)
1659
var a=l.slice(0, maxsplit)
1660
var b=l.slice(maxsplit, l.length)
Sep 5, 2014
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)
Sep 5, 2014
1678
var prefixes = $ns['prefix']
1679
if(!isinstance(prefixes,_b_.tuple)){prefixes=[prefixes]}
1680
var start = $ns['start']
1681
var end = $ns['end']
Sep 5, 2014
1682
var s = self.substr(start,end+1)
1683
1684
for (var i=0, _len_i = prefixes.length; i < _len_i; i++) {
Sep 5, 2014
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) {
1708
var res = [], pos=0
Sep 5, 2014
1709
if (isinstance(table, _b_.dict)) {
1710
for (var i=0, _len_i = self.length; i < _len_i; i++) {
Sep 5, 2014
1711
var repl = _b_.dict.$dict.get(table,self.charCodeAt(i),-1)
1712
if(repl==-1){res[pos++]=self.charAt(i)}
1713
else if(repl!==None){res[pos++]=repl}
Sep 5, 2014
1714
}
1715
}
1716
return res.join('')
Sep 5, 2014
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
}
Sep 5, 2014
1735
1737
if(arg.__class__===$B.$factory){
1738
// arg is a class (the factory function)
1739
// In this case, str() doesn't use the attribute __str__ of the
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__')
1745
if(func.__func__===_b_.object.$dict.__str__){return func(arg)}
1746
return func()
1747
}
1748
Sep 5, 2014
1749
var f = getattr(arg,'__str__')
1750
// XXX fix : if not better than object.__str__, try __repr__
1751
return f()
1752
}
1753
catch(err){
1754
//console.log('err '+err)
Sep 5, 2014
1755
try{ // try __repr__
1756
var f = getattr(arg,'__repr__')
Sep 5, 2014
1758
}catch(err){
1759
if($B.debug>1){console.log(err)}
1760
console.log('Warning - no method __str__ or __repr__, default to toString', arg)
1761
return arg.toString()
Sep 5, 2014
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
1775
$B.set_func_names($StringDict)
1776
Sep 5, 2014
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(){
1789
var args = [], pos=0
Sep 5, 2014
1790
if(arguments.length>0){
1791
var args = [arguments[0].valueOf()], pos=1
1792
for(var i=1, _len_i = arguments.length; i < _len_i;i++){
1793
args[pos++]=arguments[i]
Sep 5, 2014
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
Sep 5, 2014
1881
})(__BRYTHON__)