Skip to content
Permalink
Newer
Older
100644 1801 lines (1572 sloc) 54.7 KB
Sep 5, 2014
1
;(function($B){
2
3
eval($B.InjectBuiltins())
Sep 5, 2014
4
5
var $ObjectDict = object.$dict
6
7
var $StringDict = {__class__:$B.$type,
8
__dir__:$ObjectDict.__dir__,
Sep 5, 2014
9
__name__:'str',
10
$native:true
11
}
12
13
$StringDict.__add__ = function(self,other){
14
if(!(typeof other==="string")){
15
try{return getattr(other,'__radd__')(self)}
16
catch(err){throw _b_.TypeError(
17
"Can't convert "+$B.get_class(other).__name__+" to str implicitely")}
18
}
19
return self+other
20
}
21
22
$StringDict.__contains__ = function(self,item){
23
if(!(typeof item==="string")){throw _b_.TypeError(
24
"'in <string>' requires string as left operand, not "+item.__class__)}
25
var nbcar = item.length
26
if(nbcar==0) return true // a string contains the empty string
27
if(self.length==0) return nbcar==0
28
for(var i=0, _len_i = self.length; i < _len_i;i++){
Sep 5, 2014
29
if(self.substr(i,nbcar)==item) return true
30
}
31
return false
32
}
33
34
$StringDict.__delitem__ = function(){
35
throw _b_.TypeError("'str' object doesn't support item deletion")
36
}
37
38
// __dir__must be assigned explicitely because attribute resolution for builtin
39
// classes doesn't use __mro__
40
$StringDict.__dir__ = $ObjectDict.__dir__
41
Sep 5, 2014
42
$StringDict.__eq__ = function(self,other){
43
if(other===undefined){ // compare object "self" to class "str"
44
return self===str
45
}
46
if (_b_.isinstance(other, _b_.str)) {
47
return other.valueOf() == self.valueOf()
48
}
Sep 5, 2014
49
return other===self.valueOf()
50
}
51
52
$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])}
Sep 5, 2014
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
Sep 5, 2014
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;
103
for(var i=0, _len_i = self.length; i < _len_i; i++) {
Sep 5, 2014
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
Sep 5, 2014
191
192
}
193
194
var format_sign = function(val, flags) {
195
if (flags.sign) {
196
if (val >= 0) {
197
return "+"
Sep 5, 2014
198
}
199
} else if (flags.space) {
200
if (val >= 0) {
201
return " "
202
}
203
}
204
return ""
205
}
Sep 5, 2014
206
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
}
Sep 5, 2014
212
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
}
Sep 5, 2014
230
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
}
Sep 5, 2014
235
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
}
Sep 5, 2014
240
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
}
Sep 5, 2014
256
257
// used to capture and remove trailing zeroes
258
var trailing_zeros = /(.*?)(0+)([eE].*)/
259
var leading_zeros = /\.(0*)/
260
var trailing_dot = /\.$/
Sep 5, 2014
261
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
293
} else {
294
if (flags.precision <= 1) {
295
val = val[0] + '.' + val.substring(1)
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
Sep 5, 2014
328
}
329
}
330
if (precision < dot_idx) {
331
precision = dot_idx
332
}
333
return val.toFixed(precision - dot_idx)
334
}), flags)
335
}
Sep 5, 2014
336
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)
Sep 5, 2014
402
}
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
}
Sep 5, 2014
422
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)
Sep 5, 2014
428
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
}
Sep 5, 2014
438
}
439
440
if (flags.alternate) {
441
if (ret.charAt(0) === '-') {
442
ret = "-0o" + ret.slice(1)
443
} else {
444
ret = "0o" + ret
445
}
Sep 5, 2014
446
}
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
}
Sep 5, 2014
588
}
589
}
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
}
Sep 5, 2014
632
}
633
} while (true)
Sep 5, 2014
634
}
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
}
Sep 5, 2014
680
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
}
Sep 5, 2014
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
}
Sep 5, 2014
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
}
Sep 5, 2014
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 = []
794
for(var i=1, _len_i = arguments.length; i < _len_i;i++){args.push(arguments[i])}
Sep 5, 2014
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)
803
for(var i=0, _len_i = suffixes.length; i < _len_i;i++){
Sep 5, 2014
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 = ''
835
for(var i=0, _len_i = sub.length; i < _len_i;i++){
Sep 5, 2014
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]
931
if (this._index !== undefined && !isNaN(_name)) {
Sep 5, 2014
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
945
for (var i=0, _len_i = _name_parts.length; i < _len_i; i++) {
Sep 5, 2014
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) {
998
for (var i=0, _len_i = args.length; i < _len_i; i++) {
Sep 5, 2014
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
1008
for (var i=0, _len_i = this._kwords_array.length; i < _len_i; i++) {
Sep 5, 2014
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
1020
for (var j=0, _len_j = _items.length; j < _len_j; j++) {
Sep 5, 2014
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
1030
for (var i=0, _len_i = this._nested_array.length; i < _len_i; i++) {
Sep 5, 2014
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
1042
for (var j=0, _len_j = _items.length; j < _len_j; j++) {
Sep 5, 2014
1043
var _parts = _items[j][0]
1044
var _conv = _items[j][1]
1045
var _spec = _items[j][2]
1046
1047
_spec=$format_to_legacy(_spec, _params)
Sep 5, 2014
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
}
1053
return $format_to_legacy(this._string, _params)
Sep 5, 2014
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
1061
for (var i=0, _len_i = parts.length; i < _len_i; i++) {
Sep 5, 2014
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
1078
value = $format_to_legacy((conv == 'r') && '%r' || '%s', value)
Sep 5, 2014
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
1112
var _is_float = isinstance(value, _b_.float)
Sep 5, 2014
1113
var _is_integer = isinstance(value, _b_.int)
1114
var _is_numeric = _is_float || _is_integer
Sep 5, 2014
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
1164
_rv = $format_to_legacy(_rv, value)
Sep 5, 2014
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) {
1180
if (! _is_float && (_align == '=' || (_zero && ! _align))) {
Sep 5, 2014
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
'|(?:}})+(?!})' +
1294
'|{(?:[^{}](?:[^{}]+|{[^{}]*})*)?})', 'g'
Sep 5, 2014
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])}
Sep 5, 2014
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
1453
for(var i=0, _len_i = from.source.length; i < _len_i; i++) {
Sep 5, 2014
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++) {
1461
_b_.dict.$dict.__setitem__(_d, i, _t[i])
Sep 5, 2014
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 = "[.*+?|()$^"
1479
for(var i=0, _len_i = specials.length; i < _len_i;i++){
Sep 5, 2014
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");
Sep 5, 2014
1498
}
1499
}
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;
Sep 5, 2014
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 = []
1573
for(var i=1, _len_i = arguments.length; i < _len_i;i++){args.push(arguments[i])}
Sep 5, 2014
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]}
1578
maxsplit = _b_.dict.$dict.get($ns['kw'],'maxsplit',maxsplit)
Sep 5, 2014
1579
1580
var array=$StringDict.split(self)
1581
1582
var array=$StringDict.split(self, sep)
Sep 5, 2014
1583
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
Sep 5, 2014
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 = []
1603
for(var i=1, _len_i = arguments.length; i < _len_i;i++){args.push(arguments[i])}
Sep 5, 2014
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)
1609
if(sep=='') throw _b_.ValueError('empty separator')
Sep 5, 2014
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 = ''
1641
for(var i=0, _len_i = sep.length; i < _len_i;i++){
Sep 5, 2014
1642
switch(sep.charAt(i)) {
1643
case '*':
Feb 9, 2015
1644
case '+':
Sep 5, 2014
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)
1668
var a=l.slice(0, maxsplit)
1669
var b=l.slice(maxsplit, l.length)
Sep 5, 2014
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
1691
for (var i=0, _len_i = prefixes.length; i < _len_i; i++) {
Sep 5, 2014
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)) {
1717
for (var i=0, _len_i = self.length; i < _len_i; i++) {
Sep 5, 2014
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__')
Sep 5, 2014
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
1765
$B.set_func_names($StringDict)
1766
Sep 5, 2014
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()]
1782
for(var i=1, _len_i = arguments.length; i < _len_i;i++){
Sep 5, 2014
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__)