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