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