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