1 #### /^.$/
2 shopt -s ysh:all
3 var pat = ''
4
5 setvar pat = /^.$/
6 echo pat=$pat
7
8 setvar pat = /%start dot %end/
9 echo pat=$pat
10
11 if ('' ~ pat) { # ERE syntax
12 echo yes
13 } else {
14 echo no
15 }
16 # $pat is same as pat
17 if ('f' ~ pat) { # ERE syntax
18 echo yes
19 } else {
20 echo no
21 }
22
23 ## STDOUT:
24 pat=^.$
25 pat=^.$
26 no
27 yes
28 ## END
29
30
31 #### /.+/
32 shopt -s ysh:all
33
34 var pat = /.+/
35 echo $pat
36
37 var s = 'foo'
38 if (s ~ pat) { # ERE syntax
39 echo yes
40 }
41 var empty = ''
42 if (empty ~ pat) { echo yes } else { echo no }
43 ## STDOUT:
44 .+
45 yes
46 no
47 ## END
48
49 #### Repeat {1,3} etc.
50 var pat = null
51
52 setvar pat = /d{2}/
53 echo $pat
54 setvar pat = /d{1,3}/
55 echo $pat
56 setvar pat = /d{1,}/
57 echo $pat
58 setvar pat = /d{,3}/
59 echo $pat
60
61
62 ## STDOUT:
63 [[:digit:]]{2}
64 [[:digit:]]{1,3}
65 [[:digit:]]{1,}
66 [[:digit:]]{,3}
67 ## END
68
69
70 #### d+ digit+ !d+ !digit+
71 shopt -s ysh:all
72
73 var pat = ''
74
75 setvar pat = /d+/
76 echo $pat
77 if ('42' ~ pat) { echo yes }
78
79 var empty = ''
80 if (empty ~ pat) { echo yes } else { echo no }
81
82 setvar pat = /digit+/
83 echo $pat
84 setvar pat = /!d+/
85 echo $pat
86 setvar pat = /!digit+/
87 echo $pat
88
89
90 ## STDOUT:
91 [[:digit:]]+
92 yes
93 no
94 [[:digit:]]+
95 [^[:digit:]]+
96 [^[:digit:]]+
97 ## END
98
99 #### Alternation and sequence
100 var pat = ''
101 setvar pat = /s d+ | w*/
102 echo $pat
103 setvar pat = /s d+ or w*/
104 echo $pat
105 ## STDOUT:
106 [[:space:]][[:digit:]]+|[[:alpha:][:digit:]_]*
107 [[:space:]][[:digit:]]+|[[:alpha:][:digit:]_]*
108 ## END
109
110 #### Char Class Ranges
111 shopt -s ysh:all
112
113 var pat = ''
114 setvar pat = /[0-9 a-f]+/
115 echo $pat
116 # This is equivalent
117 setvar pat = /['0' - '9' 'a' - 'f']+/
118 echo $pat
119
120 if ('0123' ~ pat) { echo yes } else { echo no }
121 if ('zzz' ~ pat) { echo yes } else { echo no }
122 if ('' ~ pat) { echo yes } else { echo no }
123 ## STDOUT:
124 [0-9a-f]+
125 [0-9a-f]+
126 yes
127 no
128 no
129 ## END
130
131 #### Char Class Set
132 shopt -s ysh:all
133 var pat = ''
134
135 # This is NOT allowed
136 # setvar pat = /[a b c]+/
137
138 setvar pat = /['abc']+/
139 echo $pat
140
141 if ('cbcb' ~ pat) { echo yes } else { echo no }
142 if ('0123' ~ pat) { echo yes } else { echo no }
143 if ('' ~ pat) { echo yes } else { echo no }
144 ## STDOUT:
145 [abc]+
146 yes
147 no
148 no
149 ## END
150
151 #### Range with escaped characters
152 shopt -s ysh:all
153
154 var pat = null
155
156 setvar pat = / [ \x01 - \x0f ] /
157 echo $pat | od -A n -t x1
158
159 ## STDOUT:
160 5b 01 2d 0f 5d 0a
161 ## END
162
163
164 #### Group ()
165 shopt -s ysh:all
166 var pat = ''
167
168 setvar pat = /(%start s or d d)/
169 echo $pat
170
171 if (' foo' ~ pat) { echo yes } else { echo no }
172 if ('-00-' ~ pat) { echo yes } else { echo no }
173 if ('foo' ~ pat) { echo yes } else { echo no }
174
175 ## STDOUT:
176 (^[[:space:]]|[[:digit:]][[:digit:]])
177 yes
178 yes
179 no
180 ## END
181
182 #### Capture is acceptable as a group
183 shopt -s ysh:all
184 var pat = /<capture %start s | d d>/
185 echo $pat
186 ## STDOUT:
187 (^[[:space:]]|[[:digit:]][[:digit:]])
188 ## END
189
190 #### literal ''
191 shopt -s ysh:all
192 var pat = ''
193
194 setvar pat = /'abc' 'def'/
195 echo $pat
196
197 #setvar pat = /'abc' '^ + * ?'/
198 #echo $pat
199
200 if ('abcde' ~ pat) { echo yes } else { echo no }
201 if ('abcdef' ~ pat) { echo yes } else { echo no }
202
203 ## STDOUT:
204 abcdef
205 no
206 yes
207 ## END
208
209 #### Single quotes and splicing (do what "foo $x ${x}" used to)
210 shopt -s ysh:all
211 var pat = ''
212
213 var x = 'x'
214 var y = 'y'
215 setvar pat = / @x @x 'abc' @x @y /
216 echo $pat
217
218 if ('xxabcx' ~ pat) { echo yes } else { echo no }
219 if ('xxabcxyf' ~ pat) { echo yes } else { echo no }
220
221 ## STDOUT:
222 xxabcxy
223 no
224 yes
225 ## END
226
227 #### @splice
228 shopt -s ysh:all
229 var d = /d+/;
230 var ip = / @d '.' @d '.' @d '.' @d /
231 echo $ip
232 if ('0.0.0.0' ~ ip) { echo yes } else { echo no }
233 if ('0.0.0' ~ ip) { echo yes } else { echo no }
234 ## STDOUT:
235 [[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+
236 yes
237 no
238 ## END
239
240 #### splice with capital letters
241 shopt -s ysh:all
242 var D = /d+/;
243 var ip = / D '.' D '.' D '.' D /
244 echo $ip
245 if ('0.0.0.0' ~ ip) { echo yes } else { echo no }
246 if ('0.0.0' ~ ip) { echo yes } else { echo no }
247 ## STDOUT:
248 [[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+
249 yes
250 no
251 ## END
252
253 #### Repeated String Literal With Single Char
254 shopt -s ysh:all
255
256 var literal = 'f'
257 var pat = null
258
259 setvar pat = / %start @literal+ %end /
260 echo $pat
261 setvar pat = / %start (@literal)+ %end /
262 echo $pat
263
264 if ('fff' ~ pat) { echo yes }
265 if ('foo' !~ pat) { echo no }
266
267 ## STDOUT:
268 ^f+$
269 ^(f)+$
270 yes
271 no
272 ## END
273
274 #### Error when unparenthesized string of more than one character is repeated
275 shopt -s ysh:all
276
277 var literal = 'foo'
278 var pat = null
279
280 setvar pat = / %start @literal+ %end /
281 echo $pat
282 setvar pat = / %start (@literal)+ %end /
283 echo $pat
284
285 if ('foofoo' ~ pat) { echo yes }
286 if ('foof' !~ pat) { echo no }
287
288 ## status: 1
289 ## stdout-json: ""
290
291 #### Instead of $'foo\\bar' use 'foo' \\ 'bar'
292 shopt -s ysh:all
293 var pat = /'foo' \\ 'bar'/
294 echo $pat
295
296 if (r'foo\bar' ~ pat) { echo yes }
297 if (r'foo.bar' !~ pat) { echo no }
298 ## STDOUT:
299 foo\\bar
300 yes
301 no
302 ## END
303
304 #### Negation of Character Class ![a-z]
305 shopt -s ysh:all
306
307 var pat = / ![ a-z ] /
308 echo $pat
309
310 if ('0' ~ pat) { echo yes }
311 if ('a' !~ pat) { echo no }
312
313 ## STDOUT:
314 [^a-z]
315 yes
316 no
317 ## END
318
319 #### Posix and Perl class in class literals
320 shopt -s ysh:all
321
322 var pat = null
323
324 setvar pat = / [ space 'z' ] /
325 echo $pat
326 #setvar pat = / [ ~space 'z' ] /
327 #echo $pat
328
329 # PROBLEM: can't negate individual POSIX classes. They would have to be a Perl
330 # class to be \D or \S.
331 # [[:space:]z] negates the whole thing!
332 # [^[:space:]]
333
334 setvar pat = / [ digit 'z' ] /
335 echo $pat
336 #setvar pat = / [ ~digit 'z' ] /
337 #echo $pat
338
339 ## STDOUT:
340 [[:space:]z]
341 [[:digit:]z]
342 ## END
343
344 #### [!d] can't be negated because it's a literal character
345 setvar pat = / [ !d 'z' ] /
346 echo $pat
347 ## status: 2
348 ## stdout-json: ""
349
350 #### [!digit] can't be negated in POSIX ERE (but yes in Perl)
351 var pat = null
352 setvar pat = / [ !digit 'z' ] /
353 echo $pat
354 ## status: 1
355 ## stdout-json: ""
356
357 #### Operator chars in char classes (bash-like)
358
359 pat='[-]'
360 [[ '-' =~ $pat ]] && echo hyphen
361 [[ '\' =~ $pat ]] && echo FAIL
362
363 pat='[\]'
364 [[ '\' =~ $pat ]] && echo backslash
365 [[ '-' =~ $pat ]] && echo FAIL
366
367 pat='[]]'
368 [[ ']' =~ $pat ]] && echo 'right bracket'
369 [[ '[' =~ $pat ]] && echo FAIL
370
371 pat='[[]'
372 [[ '[' =~ $pat ]] && echo 'left bracket'
373 [[ ']' =~ $pat ]] && echo FAIL
374
375 pat='[.]'
376 [[ '.' =~ $pat ]] && echo period
377 [[ '\' =~ $pat ]] && echo FAIL
378
379 pat='[\^]'
380 [[ '^' =~ $pat ]] && echo caret
381 [[ '\' =~ $pat ]] && echo 'no way to have [^]'
382
383 ## STDOUT:
384 hyphen
385 backslash
386 right bracket
387 left bracket
388 period
389 caret
390 no way to have [^]
391 ## END
392
393 #### Operator chars in char classes (eggex)
394 shopt --set ysh:upgrade
395
396 var pat = / ['-'] /
397 #echo PAT=$pat
398 if ('-' ~ pat) { echo hyphen }
399 if (b'\\' ~ pat) { echo FAIL }
400
401 var pat = / [ \\ ] /
402 [[ '\' =~ $pat ]] && echo backslash
403 [[ '-' =~ $pat ]] && echo FAIL
404
405 var pat = / [ ']' ] /
406 [[ ']' =~ $pat ]] && echo 'right bracket'
407 [[ '[' =~ $pat ]] && echo FAIL
408
409 var pat = / [ '[' ] /
410 [[ '[' =~ $pat ]] && echo 'left bracket'
411 [[ ']' =~ $pat ]] && echo FAIL
412
413 var pat = / [ '.' ] /
414 [[ '.' =~ $pat ]] && echo period
415 [[ '\' =~ $pat ]] && echo FAIL
416
417 var pat = / [ \\ '^' ] /
418 [[ '^' =~ $pat ]] && echo caret
419 [[ '\' =~ $pat ]] && echo 'no way to have [^]'
420
421
422 ## STDOUT:
423 hyphen
424 backslash
425 right bracket
426 left bracket
427 period
428 caret
429 no way to have [^]
430 ## END
431
432 #### Matching ] and \ and ' and " in character classes
433 shopt -s ysh:all
434
435 # BUG: need C strings in array literal
436 var lines = :|
437 'backslash \'
438 'rbracket ]'
439 'lbracket ['
440 "sq '"
441 'dq ""'
442 |
443
444 # Weird GNU quirk: ] has to come first!
445 # []abc] works. But [abc\]] does NOT work. Stupid rule!
446
447 var pat = / [ ']' \\ \' \" ] /
448 write pat=$pat
449 write @lines | egrep $pat
450
451 ## STDOUT:
452 pat=[]'"\\]
453 backslash \
454 rbracket ]
455 sq '
456 dq ""
457 ## END
458
459 #### Matching literal hyphen in character classes
460 shopt -s ysh:all
461
462 var literal = '-'
463 var pat = / [ 'a' 'b' @literal ] /
464 write pat=$pat
465 write 'c-d' 'ab' 'cd' | grep $pat
466 ## STDOUT:
467 pat=[ab-]
468 c-d
469 ab
470 ## END
471
472 #### Char class special: ^ - ] \
473
474 # See demo/ere-char-class-literals.sh
475 #
476 # \ is special because of gawk
477
478 shopt -s ysh:upgrade
479
480
481 # Note: single caret disalowed
482 var caret = / ['^' 'x'] /
483 echo caret=$caret
484
485 var caret2 = / [ \x5e 'x'] /
486 echo caret2=$caret2
487
488 var caret3 = / [ \u{5e} 'x'] /
489 echo caret3=$caret3
490
491 if ('x' ~ caret3) {
492 echo 'match x'
493 }
494 if ('^' ~ caret3) {
495 echo 'match ^'
496 }
497
498 echo ---
499
500 var hyphen = / ['a' '-' 'b'] /
501 echo hyphen=$hyphen
502
503 var hyphen2 = / ['a' \x2d 'b' ] /
504 echo hyphen2=$hyphen2
505
506 if ('-' ~ hyphen2) {
507 echo 'match -'
508 }
509
510 if ('a' ~ hyphen2) {
511 echo 'match a'
512 }
513
514 if ('c' ~ hyphen2) {
515 echo 'match c'
516 }
517
518 echo ---
519
520 var rbracket = / [ '[' ']' ] /
521 echo rbracket=$rbracket
522
523 var rbracket2 = / [ \x5b \x5d ] /
524 echo rbracket2=$rbracket2
525
526 if ('[' ~ rbracket2) {
527 echo 'match ['
528 }
529
530 if (']' ~ rbracket2) {
531 echo 'match ]'
532 }
533
534 echo ---
535
536 var backslash = / [ 'x' \\ 'n' ] /
537 echo backslash=$backslash
538
539 var backslash2 = / [ 'x' \x5c 'n' ] /
540 echo backslash2=$backslash2
541
542 var backslash3 = / [ 'x' $'\\' 'n' ] /
543 echo backslash3=$backslash3
544
545 if ('x' ~ backslash3) {
546 echo 'match x'
547 }
548
549 if ('n' ~ backslash3) {
550 echo 'match n'
551 }
552
553 if (b'\\' ~ backslash3) {
554 echo 'match backslash'
555 }
556
557 if ($'\n' ~ backslash3) {
558 echo 'match nnewline'
559 }
560
561
562 ## STDOUT:
563 caret=[x^]
564 caret2=[x^]
565 caret3=[x^]
566 match x
567 match ^
568 ---
569 hyphen=[ab-]
570 hyphen2=[ab-]
571 match -
572 match a
573 ---
574 rbracket=[][]
575 rbracket2=[][]
576 match [
577 match ]
578 ---
579 backslash=[xn\\]
580 backslash2=[xn\\]
581 backslash3=[xn\\]
582 match x
583 match n
584 match backslash
585 ## END
586
587
588 #### character class with digit [\\0] should not crash (issue #2380)
589 shopt -s ysh:all
590
591 var pat = /[\\0]/
592 echo "pattern: $pat"
593
594 # Test matching
595 pp test_ ('0' ~ pat)
596 pp test_ ('1' ~ pat)
597 pp test_ (b'\\' ~ pat)
598
599 echo ---
600
601 # Also test other digits in character class
602 var digits = /[0-9]/
603 echo $digits
604 pp test_ ('5' ~ digits)
605 pp test_ ('x' ~ digits)
606
607
608 ## STDOUT:
609 pattern: [0\\]
610 (Bool) true
611 (Bool) false
612 (Bool) true
613 ---
614 [0-9]
615 (Bool) true
616 (Bool) false
617 ## END
618
619 #### Multiple digits like [25] are invalid
620
621 # synonyms
622 var pat = /[2 5]/
623 echo $pat
624 var pat = /[2 '5']/
625 echo $pat
626
627 var pat = /[25]/
628 echo $pat
629
630 ## status: 2
631 ## STDOUT:
632 [25]
633 [25]
634 ## END
635
636 #### Negation of digit not allowed
637
638 var digits = /[!2]/
639
640 ## status: 2
641 ## STDOUT:
642 ## END