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