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