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