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