home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / unix / question / 9628 < prev    next >
Encoding:
Internet Message Format  |  1992-07-30  |  2.7 KB

  1. Path: sparky!uunet!zaphod.mps.ohio-state.edu!sdd.hp.com!usc!nic!netlabs!lwall
  2. From: lwall@netlabs.com (Larry Wall)
  3. Newsgroups: comp.unix.questions
  4. Subject: Re: Regular Expressions with [fe]grep (AGAIN)
  5. Message-ID: <1992Jul31.065335.22660@netlabs.com>
  6. Date: 31 Jul 92 06:53:35 GMT
  7. References: <1992Jul30.110331.3647@news.acns.nwu.edu>
  8. Sender: news@netlabs.com
  9. Organization: NetLabs, Inc.
  10. Lines: 82
  11. Nntp-Posting-Host: scalpel.netlabs.com
  12.  
  13. In article <1992Jul30.110331.3647@news.acns.nwu.edu> navarra@casbah.acns.nwu.edu (John Navarra) writes:
  14. : Now, however, I want to change each '0' to a '123':
  15. : 123
  16. : 123123
  17. : 123123123
  18. : 123123123123
  19. : 123123123123123
  20. : 123123123123123123
  21. : 123123123123123123123
  22. : and I want to get the same results with the pattern matching.
  23. : I want to print out the lines with one string of '123', the 
  24. : lines with two strings of '123',  or at least 1 but no more than
  25. : 3 strings of '123'  
  26. : Is there some way using a form of grep to do this? Egrep has '()' grouping
  27. : but doesn't have the \{n,m\} stuff. And grep has the opposite. Grrr. 
  28.  
  29. Outa luck with *grep.  Sorry.  Perl does what you expect:
  30.  
  31.     perl -ne "print if /^(123){1}$/"
  32.     perl -ne "print if /^(123){2}$/"
  33.     perl -ne "print if /^(123){1,3}$/"
  34.  
  35. : Secondly, what if my file looked like:
  36. : 123.105.113.13
  37. : 123.123.113.13
  38. : 123.123.123.13
  39. : 123.123.123.123
  40. : How would I print out the lines matching the following conditions:
  41. : 1) only one occurence of '123'
  42.  
  43. That's problematical, because you can't anchor with ^ and $ to keep
  44. from matching lines with more than you're interested in.  Did you
  45. mean consecutive occurrences?  Then you can say
  46.  
  47.     perl -ne 'print if /(123\.?)+/ && length($&) <= 4'
  48.  
  49. : 2) two or more occurences of '123'
  50.  
  51.     perl -ne 'print if /(123\.?){2,}/ && length($&) <= 8'
  52.  
  53. : 3) at least two but no more than 4 occurences of '123'.
  54.  
  55.     perl -ne 'print if /(123\.?){2,}/ && length($&) <= 16'
  56.  
  57. If I were forced to do it in sed, I'd do something tricksy like
  58.  
  59.     s/$/./;
  60.     s/123\./X/g
  61.     /X\{2,4\}/!d
  62.     s/X/123./
  63.     s/\.$//
  64.  
  65. It becomes somewhat simpler if you don't require consecutive
  66. occurrences, since Perl's substitute operator will return how many
  67. substitutions it did.  (I presume that you only want 123 as a complete
  68. "word", so I've used \b to assert word boundaries here.)
  69.  
  70. : 1) only one occurence of '123'
  71.  
  72.     perl -ne 'print if s/\b123\b/123/g == 1'
  73.  
  74. : 2) two or more occurences of '123'
  75.  
  76.     perl -ne 'print if s/\b123\b/123/g >= 2'
  77.  
  78. : 3) at least two but no more than 4 occurences of '123'.
  79.  
  80.     perl -ne '$count = s/\b123\b/123/g; print if $count >= 2 && $count <= 4'
  81.  
  82. In recent versions of Perl you can also do it with a g modifier on
  83. an ordinary pattern match:
  84.  
  85.     perl -ne '@c = /\b123\b/g; print if @c == 1'
  86.     etc.
  87.  
  88. Larry Wall
  89. lwall@netlabs.com
  90.