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