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