Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/python-wasm
Path: blob/main/python/pylang/src/baselib/str.py
1398 views
1
# vim:fileencoding=utf-8
2
# License: BSD
3
# Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
4
5
# globals: ρσ_kwargs_symbol, ρσ_list_decorate, ρσ_iterator_symbol, HTMLElement
6
7
# Locale can’t be changed in-flight, so we just retrieve this once.
8
# Sadly older node versions (< 8) don’t support formatToParts
9
# decimal_sep = Intl.NumberFormat() \
10
# .formatToParts(1.1) \
11
# .find(def(part): return part.type == 'decimal';) \
12
# .value
13
decimal_sep = (1.1).toLocaleString()[1]
14
15
def ρσ_repr_js_builtin(x, as_array):
16
ans = v'[]'
17
b = '{}'
18
if as_array:
19
b = '[]'
20
for v'var i = 0; i < x.length; i++':
21
ans.push(ρσ_repr(x[i]))
22
else:
23
keys = Object.keys(x)
24
for v'var k = 0; k < keys.length; k++':
25
key = keys[k]
26
ans.push(ρσ_repr(key) + ': ' + ρσ_repr(x[key]))
27
return b[0] + ans.join(', ') + b[1]
28
29
def ρσ_html_element_to_string(elem):
30
attrs = v'[]'
31
for attr in elem.attributes:
32
if attr.specified:
33
val = attr.value
34
if val.length > 10:
35
val = val[:15] + '...'
36
val = JSON.stringify(val)
37
attrs.push(f'{attr.name}={val}')
38
attrs = (' ' + attrs.join(' ')) if attrs.length else ''
39
ans = f'<{elem.tagName}{attrs}>'
40
return ans
41
42
def ρσ_repr(x):
43
if x is None:
44
return 'None'
45
if x is undefined:
46
return 'undefined'
47
ans = x
48
if v'typeof x.__repr__ === "function"':
49
ans = x.__repr__()
50
elif x is True or x is False:
51
ans = 'True' if x else 'False'
52
elif Array.isArray(x):
53
ans = ρσ_repr_js_builtin(x, True)
54
elif jstype(x) is 'string': # python uses single quotes for repr(string)
55
ans = "'" + x + "'"
56
elif jstype(x) is 'function':
57
ans = x.toString()
58
elif jstype(x) is 'object' and not x.toString:
59
# Assume this is a dictionary
60
ans = ρσ_repr_js_builtin(x)
61
else:
62
name = Object.prototype.toString.call(x).slice(8, -1)
63
if "Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".indexOf(name) != -1:
64
return name + '([' + x.map(def(i): return str.format('0x{:02x}', i);).join(', ') + '])'
65
if jstype(HTMLElement) is not 'undefined' and v'x instanceof HTMLElement':
66
ans = ρσ_html_element_to_string(x)
67
else:
68
ans = x.toString() if v'typeof x.toString === "function"' else x
69
if ans is '[object Object]':
70
# Assume this is a dictionary
71
return ρσ_repr_js_builtin(x)
72
try:
73
ans = JSON.stringify(x)
74
except:
75
pass
76
return ans + '' # Ensures we return an object of type string (i.e. primitive value) rather than a String object
77
78
def ρσ_str(x):
79
if x is None:
80
return 'None'
81
if x is undefined:
82
return 'undefined'
83
ans = x
84
if v'typeof x.__str__ === "function"':
85
ans = x.__str__()
86
elif v'typeof x.__repr__ === "function"':
87
ans = x.__repr__()
88
elif x is True or x is False:
89
ans = 'True' if x else 'False'
90
elif Array.isArray(x):
91
ans = ρσ_repr_js_builtin(x, True)
92
elif v'typeof x.toString === "function"':
93
name = Object.prototype.toString.call(x).slice(8, -1)
94
if "Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".indexOf(name) != -1:
95
return name + '([' + x.map(def(i): return str.format('0x{:02x}', i);).join(', ') + '])'
96
if jstype(HTMLElement) is not 'undefined' and v'x instanceof HTMLElement':
97
ans = ρσ_html_element_to_string(x)
98
else:
99
ans = x.toString()
100
if ans is '[object Object]':
101
# Assume this is a dictionary
102
ans = ρσ_repr_js_builtin(x)
103
elif jstype(x) is 'object' and not x.toString:
104
# Assume this is a dictionary
105
ans = ρσ_repr_js_builtin(x)
106
return ans + '' # Ensures we return an object of type string (i.e. primitive value) rather than a String object
107
108
define_str_func = def(name, func):
109
ρσ_str.prototype[name] = func
110
ρσ_str[name] = f = func.call.bind(func)
111
if func.__argnames__:
112
Object.defineProperty(f, '__argnames__', {'value':v"['string']".concat(func.__argnames__)})
113
114
ρσ_orig_split, ρσ_orig_replace = String.prototype.split.call.bind(String.prototype.split), String.prototype.replace.call.bind(String.prototype.replace)
115
116
# format() {{{
117
define_str_func('format', def ():
118
template = this
119
if template is undefined:
120
raise TypeError("Template is required")
121
args = Array.prototype.slice.call(arguments)
122
kwargs = {}
123
if args[-1] and args[-1][ρσ_kwargs_symbol] is not undefined:
124
kwargs = args[-1]
125
args = args[:-1]
126
127
explicit = implicit = False
128
idx = 0
129
split = ρσ_orig_split
130
131
if ρσ_str.format._template_resolve_pat is undefined:
132
ρσ_str.format._template_resolve_pat = /[.\[]/
133
134
def resolve(arg, object):
135
if not arg:
136
return object
137
first, arg = arg[0], arg[1:]
138
key = split(arg, ρσ_str.format._template_resolve_pat, 1)[0]
139
rest = arg[key.length:]
140
ans = object[key[:-1]] if first is '[' else getattr(object, key)
141
if ans is undefined:
142
raise KeyError(key[:-1] if first is '[' else key)
143
return resolve(rest, ans)
144
145
def resolve_format_spec(format_spec):
146
if ρσ_str.format._template_resolve_fs_pat is undefined:
147
ρσ_str.format._template_resolve_fs_pat = /[{]([a-zA-Z0-9_]+)[}]/g
148
return format_spec.replace(ρσ_str.format._template_resolve_fs_pat, def (match, key):
149
if not Object.prototype.hasOwnProperty.call(kwargs, key):
150
return ''
151
return '' + kwargs[key]
152
)
153
154
def set_comma(ans, comma):
155
if comma is not ',':
156
sep = 1234
157
sep = sep.toLocaleString(undefined, v'{useGrouping: true}')[1]
158
ans = str.replace(ans, sep, comma)
159
return ans
160
161
def safe_comma(value, comma):
162
try:
163
return set_comma(value.toLocaleString(undefined, v'{useGrouping: true}'), comma)
164
except:
165
return value.toString(10)
166
167
168
def safe_fixed(value, precision, comma):
169
if not comma:
170
return value.toFixed(precision)
171
try:
172
return set_comma(value.toLocaleString(undefined, v'{useGrouping: true, minimumFractionDigits: precision, maximumFractionDigits: precision}'), comma)
173
except:
174
return value.toFixed(precision)
175
176
177
def apply_formatting(value, format_spec):
178
if format_spec.indexOf('{') is not -1:
179
format_spec = resolve_format_spec(format_spec)
180
if ρσ_str.format._template_format_pat is undefined:
181
ρσ_str.format._template_format_pat = ///
182
([^{}](?=[<>=^]))?([<>=^])? # fill & align
183
([-+\x20])? # sign
184
(\#)? # integer base specifier
185
(0)? # zero-padding
186
(\d+)? # width
187
([,_])? # use a grouping (thousands) seperator
188
(?:\.(\d+))? # precision
189
([bcdeEfFgGnosxX%])? # type
190
///
191
192
try:
193
fill, align, sign, fhash, zeropad, width, comma, precision, ftype = format_spec.match(ρσ_str.format._template_format_pat)[1:]
194
except TypeError:
195
return value
196
if zeropad:
197
fill = fill or '0'
198
align = align or '='
199
else:
200
fill = fill or ' '
201
align = align or '>'
202
is_numeric = v'Number(value) === value'
203
is_int = is_numeric and v'value % 1 === 0'
204
precision = parseInt(precision, 10)
205
lftype = (ftype or '').toLowerCase()
206
207
if ftype is 'n':
208
is_numeric = True
209
if is_int:
210
if comma:
211
raise ValueError("Cannot specify ',' with 'n'")
212
value = parseInt(value, 10).toLocaleString()
213
else:
214
value = parseFloat(value).toLocaleString()
215
216
elif v"['b', 'c', 'd', 'o', 'x']".indexOf(lftype) is not -1:
217
value = parseInt(value, 10)
218
is_numeric = True
219
if not isNaN(value):
220
if ftype is 'b':
221
value = v'(value >>> 0).toString(2)'
222
if fhash:
223
value = '0b' + value
224
elif ftype is 'c':
225
if value > 0xFFFF:
226
code = value - 0x10000
227
value = String.fromCharCode(0xD800+(code>>10), 0xDC00+(code&0x3FF))
228
else:
229
value = String.fromCharCode(value)
230
elif ftype is 'd':
231
if comma:
232
value = safe_comma(value, comma)
233
else:
234
value = value.toString(10)
235
elif ftype is 'o':
236
value = value.toString(8)
237
if fhash:
238
value = '0o' + value
239
elif lftype is 'x':
240
value = value.toString(16)
241
value = value.toLowerCase() if ftype is 'x' else value.toUpperCase()
242
if fhash:
243
value = '0x' + value
244
245
elif v"['e','f','g','%']".indexOf(lftype) is not -1:
246
is_numeric = True
247
value = parseFloat(value)
248
prec = 6 if isNaN(precision) else precision
249
if lftype is 'e':
250
value = value.toExponential(prec)
251
value = value.toUpperCase() if ftype is 'E' else value.toLowerCase()
252
elif lftype is 'f':
253
value = safe_fixed(value, prec, comma)
254
value = value.toUpperCase() if ftype is 'F' else value.toLowerCase()
255
elif lftype is '%':
256
value *= 100
257
value = safe_fixed(value, prec, comma) + '%'
258
elif lftype is 'g':
259
prec = max(1, prec)
260
exp = parseInt(split(value.toExponential(prec - 1).toLowerCase(), 'e')[1], 10)
261
if -4 <= exp < prec:
262
value = safe_fixed(value, prec - 1 - exp, comma)
263
else:
264
value = value.toExponential(prec - 1)
265
value = value.replace(/0+$/g, '')
266
if value[-1] is decimal_sep:
267
value = value[:-1]
268
if ftype is 'G':
269
value = value.toUpperCase()
270
271
else:
272
if comma:
273
value = parseInt(value, 10)
274
if isNaN(value):
275
raise ValueError('Must use numbers with , or _')
276
value = safe_comma(value, comma)
277
value += '' # Ensure we have a string
278
if not isNaN(precision):
279
value = value[:precision]
280
281
value += '' # Ensure we have a string
282
283
if is_numeric and sign:
284
nval = v'Number(value)'
285
is_positive = not isNaN(nval) and nval >= 0
286
if is_positive and (sign is ' ' or sign is '+'):
287
value = sign + value
288
289
def repeat(char, num):
290
return v'(new Array(num+1)).join(char)'
291
292
if is_numeric and width and width[0] is '0':
293
width = width[1:]
294
fill, align = '0', '='
295
296
width = parseInt(width or '-1', 10)
297
if isNaN(width):
298
raise ValueError('Invalid width specification: ' + width)
299
300
if fill and value.length < width:
301
if align is '<':
302
value = value + repeat(fill, width - value.length)
303
elif align is '>':
304
value = repeat(fill, width - value.length) + value
305
elif align is '^':
306
left = (width - value.length) // 2
307
right = width - left - value.length
308
value = repeat(fill, left) + value + repeat(fill, right)
309
elif align is '=':
310
if value[0] in "+- ":
311
value = value[0] + repeat(fill, width - value.length) + value[1:]
312
else:
313
value = repeat(fill, width - value.length) + value
314
else:
315
raise ValueError('Unrecognized alignment: ' + align)
316
317
return value
318
319
def parse_markup(markup):
320
key = transformer = format_spec = ''
321
pos = 0
322
state = 0
323
while pos < markup.length:
324
ch = markup[pos]
325
if state is 0:
326
if ch is '!':
327
state = 1
328
elif ch is ':':
329
state = 2
330
else:
331
key += ch
332
elif state is 1:
333
if ch is ':':
334
state = 2
335
else:
336
transformer += ch
337
else:
338
format_spec += ch
339
pos += 1
340
return key, transformer, format_spec
341
342
def render_markup(markup):
343
nonlocal explicit, implicit, idx
344
key, transformer, format_spec = parse_markup(markup)
345
if transformer and v"['a', 'r', 's']".indexOf(transformer) is -1:
346
raise ValueError('Unknown conversion specifier: ' + transformer)
347
ends_with_equal = key.endsWith('=')
348
if ends_with_equal:
349
key = key[:-1]
350
lkey = key.length and split(key, /[.\[]/, 1)[0]
351
if lkey:
352
explicit = True
353
if implicit:
354
raise ValueError('cannot switch from automatic field numbering to manual field specification')
355
nvalue = parseInt(lkey)
356
object = kwargs[lkey] if isNaN(nvalue) else args[nvalue]
357
if object is undefined:
358
if isNaN(nvalue):
359
raise KeyError(lkey)
360
raise IndexError(lkey)
361
object = resolve(key[lkey.length:], object)
362
else:
363
implicit = True
364
if explicit:
365
raise ValueError('cannot switch from manual field specification to automatic field numbering')
366
if idx >= args.length:
367
raise IndexError('Not enough arguments to match template: ' + template)
368
object = args[idx]
369
idx += 1
370
if jstype(object) is 'function':
371
object = object()
372
ans = '' + object
373
if format_spec:
374
ans = apply_formatting(ans, format_spec)
375
if ends_with_equal:
376
ans = f'{key}={ans}'
377
return ans
378
379
380
ans = ''
381
pos = 0
382
in_brace = 0
383
markup = ''
384
while pos < template.length:
385
ch = template[pos]
386
if in_brace:
387
if ch is '{':
388
in_brace += 1
389
markup += '{'
390
elif ch is '}':
391
in_brace -= 1
392
if in_brace > 0:
393
markup += '}'
394
else:
395
ans += render_markup(markup)
396
else:
397
markup += ch
398
else:
399
if ch is '{':
400
if template[pos+1] is '{':
401
pos += 1
402
ans += '{'
403
else:
404
in_brace = 1
405
markup = ''
406
else:
407
ans += ch
408
if ch is '}' and template[pos+1] is '}':
409
pos += 1
410
411
pos += 1
412
413
if in_brace:
414
raise ValueError("expected '}' before end of string")
415
416
return ans
417
)
418
# }}}
419
420
define_str_func('capitalize', def ():
421
string = this
422
if string:
423
string = string[0].toUpperCase() + string[1:].toLowerCase()
424
return string
425
)
426
427
define_str_func('center', def(width, fill):
428
left = (width - this.length) // 2
429
right = width - left - this.length # noqa:unused-local
430
fill = fill or ' '
431
return v'new Array(left+1).join(fill)' + this + v'new Array(right+1).join(fill)'
432
)
433
434
define_str_func('count', def(needle, start, end):
435
string = this
436
start = start or 0
437
end = end or string.length
438
if start < 0 or end < 0:
439
string = string[start:end]
440
start, end = 0, string.length
441
pos = start
442
step = needle.length
443
if not step:
444
return 0
445
ans = 0
446
while pos is not -1:
447
pos = string.indexOf(needle, pos)
448
if pos is not -1:
449
ans += 1
450
pos += step
451
return ans
452
)
453
454
define_str_func('endswith', def(suffixes, start, end):
455
string = this
456
start = start or 0
457
if jstype(suffixes) is 'string':
458
suffixes = v'[suffixes]'
459
if end is not undefined:
460
string = string[:end]
461
for v'var i = 0; i < suffixes.length; i++':
462
q = suffixes[i] # noqa:undef
463
if string.indexOf(q, Math.max(start, string.length - q.length)) is not -1:
464
return True
465
return False
466
)
467
468
define_str_func('startswith', def(prefixes, start, end):
469
start = start or 0
470
if jstype(prefixes) is 'string':
471
prefixes = v'[prefixes]'
472
for v'var i = 0; i < prefixes.length; i++':
473
prefix = prefixes[i] # noqa:undef
474
end = this.length if end is undefined else end
475
if end - start >= prefix.length and prefix is this[start:start + prefix.length]:
476
return True
477
return False
478
)
479
480
define_str_func('find', def(needle, start, end):
481
while start < 0:
482
start += this.length
483
ans = this.indexOf(needle, start)
484
if end is not undefined and ans is not -1:
485
while end < 0:
486
end += this.length
487
if ans >= end - needle.length:
488
return -1
489
return ans
490
)
491
492
define_str_func('rfind', def(needle, start, end):
493
while end < 0:
494
end += this.length
495
ans = this.lastIndexOf(needle, end - 1)
496
if start is not undefined and ans is not -1:
497
while start < 0:
498
start += this.length
499
if ans < start:
500
return -1
501
return ans
502
)
503
504
define_str_func('index', def(needle, start, end):
505
ans = ρσ_str.prototype.find.apply(this, arguments)
506
if ans is -1:
507
raise ValueError('substring not found')
508
return ans
509
)
510
511
define_str_func('rindex', def(needle, start, end):
512
ans = ρσ_str.prototype.rfind.apply(this, arguments)
513
if ans is -1:
514
raise ValueError('substring not found')
515
return ans
516
)
517
518
define_str_func('islower', def():
519
return this.length > 0 and this.toLowerCase() is this.toString()
520
)
521
522
define_str_func('isupper', def():
523
return this.length > 0 and this.toUpperCase() is this.toString()
524
)
525
526
define_str_func('isspace', def():
527
return this.length > 0 and /^\s+$/.test(this)
528
)
529
530
define_str_func('join', def(iterable):
531
if Array.isArray(iterable):
532
return iterable.join(this)
533
ans = ''
534
r = iterable.next()
535
while not r.done:
536
if ans:
537
ans += this
538
ans += r.value
539
r = iterable.next()
540
return ans
541
)
542
543
define_str_func('ljust', def(width, fill):
544
string = this
545
if width > string.length:
546
fill = fill or ' '
547
string += v'new Array(width - string.length + 1).join(fill)'
548
return string
549
)
550
551
define_str_func('rjust', def(width, fill):
552
string = this
553
if width > string.length:
554
fill = fill or ' '
555
string = v'new Array(width - string.length + 1).join(fill)' + string
556
return string
557
)
558
559
define_str_func('lower', def():
560
return this.toLowerCase()
561
)
562
563
define_str_func('upper', def():
564
return this.toUpperCase()
565
)
566
567
define_str_func('lstrip', def(chars):
568
string = this
569
pos = 0
570
chars = chars or ρσ_str.whitespace
571
while chars.indexOf(string[pos]) is not -1:
572
pos += 1
573
if pos:
574
string = string[pos:]
575
return string
576
)
577
578
define_str_func('rstrip', def(chars):
579
string = this
580
pos = string.length - 1
581
chars = chars or ρσ_str.whitespace
582
while chars.indexOf(string[pos]) is not -1:
583
pos -= 1
584
if pos < string.length - 1:
585
string = string[:pos + 1]
586
return string
587
)
588
589
define_str_func('strip', def(chars):
590
return ρσ_str.prototype.lstrip.call(ρσ_str.prototype.rstrip.call(this, chars), chars)
591
)
592
593
define_str_func('partition', def(sep):
594
idx = this.indexOf(sep)
595
if idx is -1:
596
return this, '', ''
597
return this[:idx], sep, this[idx + sep.length:]
598
)
599
600
define_str_func('rpartition', def(sep):
601
idx = this.lastIndexOf(sep)
602
if idx is -1:
603
return '', '', this
604
return this[:idx], sep, this[idx + sep.length:]
605
)
606
607
define_str_func('replace', def(old, repl, count):
608
string = this
609
if count is 1:
610
return ρσ_orig_replace(string, old, repl)
611
if count < 1:
612
return string
613
count = count or Number.MAX_VALUE
614
pos = 0
615
while count > 0:
616
count -= 1
617
idx = string.indexOf(old, pos)
618
if idx is -1:
619
break
620
pos = idx + repl.length
621
string = string[:idx] + repl + string[idx + old.length:]
622
return string
623
)
624
625
define_str_func('split', def(sep, maxsplit):
626
if maxsplit is 0:
627
return [this]
628
split = ρσ_orig_split
629
if sep is undefined or sep is None:
630
if maxsplit > 0:
631
ans = split(this, /(\s+)/)
632
extra = ''
633
parts = v'[]'
634
for v'var i = 0; i < ans.length; i++':
635
if parts.length >= maxsplit + 1:
636
extra += ans[i]
637
elif i % 2 is 0:
638
parts.push(ans[i]) # noqa:undef
639
parts[-1] += extra
640
ans = parts
641
else:
642
ans = split(this, /\s+/)
643
else:
644
if sep is '':
645
raise ValueError('empty separator')
646
ans = split(this, sep)
647
if maxsplit > 0 and ans.length > maxsplit:
648
extra = ans[maxsplit:].join(sep)
649
ans = ans[:maxsplit]
650
ans.push(extra)
651
return ρσ_list_decorate(ans)
652
)
653
654
define_str_func('rsplit', def(sep, maxsplit):
655
if not maxsplit:
656
return ρσ_str.prototype.split.call(this, sep)
657
split = ρσ_orig_split
658
if sep is undefined or sep is None:
659
if maxsplit > 0:
660
ans = v'[]'
661
is_space = /\s/
662
pos = this.length - 1
663
current = ''
664
while pos > -1 and maxsplit > 0:
665
spc = False
666
ch = this[pos]
667
while pos > -1 and is_space.test(ch):
668
spc = True
669
ch = v'this[--pos]'
670
if spc:
671
if current:
672
ans.push(current)
673
maxsplit -= 1
674
current = ch
675
else:
676
current += ch
677
pos -= 1
678
ans.push(this[:pos + 1] + current)
679
ans.reverse()
680
else:
681
ans = split(this, /\s+/)
682
else:
683
if sep is '':
684
raise ValueError('empty separator')
685
ans = v'[]'
686
pos = end = this.length
687
while pos > -1 and maxsplit > 0:
688
maxsplit -= 1
689
idx = this.lastIndexOf(sep, pos)
690
if idx is -1:
691
break
692
ans.push(this[idx + sep.length:end])
693
pos = idx - 1
694
end = idx
695
ans.push(this[:end])
696
ans.reverse()
697
return ρσ_list_decorate(ans)
698
)
699
700
define_str_func('splitlines', def(keepends):
701
split = ρσ_orig_split
702
if keepends:
703
parts = split(this, /((?:\r?\n)|\r)/)
704
ans = v'[]'
705
for v'var i = 0; i < parts.length; i++':
706
if i % 2 is 0:
707
ans.push(parts[i])
708
else:
709
ans[-1] += parts[i] # noqa:undef
710
else:
711
ans = split(this, /(?:\r?\n)|\r/)
712
return ρσ_list_decorate(ans)
713
)
714
715
define_str_func('swapcase', def():
716
ans = v'new Array(this.length)'
717
for v'var i = 0; i < ans.length; i++':
718
a = this[i]
719
# We dont care about non-BMP chars as they are not cased anyway
720
b = a.toLowerCase()
721
if a is b:
722
b = a.toUpperCase()
723
ans[i] = b # noqa:undef
724
return ans.join('')
725
)
726
727
define_str_func('zfill', def(width):
728
string = this
729
if width > string.length:
730
string = v'new Array(width - string.length + 1).join("0")' + string
731
return string
732
)
733
734
ρσ_str.ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
735
ρσ_str.ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
736
ρσ_str.ascii_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
737
ρσ_str.digits = '0123456789'
738
ρσ_str.punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
739
ρσ_str.printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
740
ρσ_str.whitespace = ' \t\n\r\x0b\x0c'
741
742
v'define_str_func = undefined'
743
v'var str = ρσ_str, repr = ρσ_repr'
744
745