Util.pm 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package Logos::Util;
  2. use 5.006;
  3. use strict;
  4. our @ISA = ('Exporter');
  5. our @EXPORT = qw(quotes fallsBetween sanitize matchedParenthesisSet nestedParenString smartSplit);
  6. our $errorhandler = \&_defaultErrorHandler;
  7. sub _defaultErrorHandler {
  8. die shift;
  9. }
  10. sub quotes {
  11. my ($line) = @_;
  12. my @quotes = ();
  13. while($line =~ /(?<!\\)\"/g) {
  14. push(@quotes, $-[0]);
  15. }
  16. return @quotes;
  17. }
  18. sub fallsBetween {
  19. my $idx = shift;
  20. while(@_ > 0) {
  21. my $start = shift;
  22. my $end = shift;
  23. return 1 if ($start < $idx && (!defined($end) || $end > $idx))
  24. }
  25. return 0;
  26. }
  27. sub sanitize {
  28. my $input = shift;
  29. my $output = $input;
  30. $output =~ s/[^\w]//g;
  31. return $output;
  32. }
  33. sub matchedParenthesisSet {
  34. my $in = shift;
  35. my $atstart = shift;
  36. $atstart = 1 if !defined $atstart;
  37. my $untilend = shift;
  38. $untilend = 0 if !defined $untilend;
  39. my @parens;
  40. if(!$atstart || $in =~ /^\s*\(/) {
  41. # If we encounter a ) that puts us back at zero, we found a (
  42. # and have reached its closing ).
  43. my $parenmatch = $in;
  44. my $pdepth = 0;
  45. my @pquotes = quotes($parenmatch);
  46. while($parenmatch =~ /[;()]/g) {
  47. next if fallsBetween($-[0], @pquotes);
  48. if($& eq "(") {
  49. if($pdepth == 0) { push(@parens, $+[0]); }
  50. $pdepth++;
  51. } elsif($& eq ")") {
  52. $pdepth--;
  53. if($pdepth == 0) { push(@parens, $+[0]); last if(!$untilend); }
  54. }
  55. }
  56. }
  57. return undef if scalar @parens == 0;
  58. # Odd number of parens means a closing paren was left off!
  59. &$errorhandler("missing closing parenthesis") if scalar @parens % 2 == 1;
  60. return @parens;
  61. }
  62. sub nestedParenString {
  63. my $in = shift;
  64. my ($opening, $closing) = matchedParenthesisSet($in);
  65. my @ret;
  66. if(defined $opening) {
  67. $ret[0] = substr($in, $opening, $closing - $opening - 1);
  68. $in = substr($in, $closing);
  69. }
  70. $ret[1] = $in;
  71. return @ret;
  72. }
  73. sub smartSplit {
  74. my $re = shift;
  75. my $in = shift;
  76. return () if !$in || $in eq "";
  77. my $limit = shift;
  78. $limit = 0 if !defined $limit;
  79. my @quotes = quotes($in);
  80. # We pass 1 for arg 3 to catch all matching parentheses until the end of the string
  81. # as smartSplit only operates on a substring.
  82. my @parens = matchedParenthesisSet($in, 0, 1);
  83. my $lstart = 0;
  84. my @pieces = ();
  85. my $piece = "";
  86. while($in =~ /$re/g) {
  87. next if (defined $parens[0] && fallsBetween($-[0], @parens)) || fallsBetween($-[0], @quotes);
  88. $piece = substr($in, $lstart, $-[0]-$lstart);
  89. push(@pieces, $piece);
  90. $lstart = $+[0];
  91. $limit--;
  92. last if($limit == 1); # One item left? Bail out and throw the rest of the string into it!
  93. }
  94. $piece = substr($in, $lstart);
  95. push(@pieces, $piece);
  96. return @pieces;
  97. }
  98. 1;