Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re^4: Grab input from the user and Open the file

by valerydolce (Novice)
on Nov 27, 2016 at 20:33 UTC ( [id://1176663]=note: print w/replies, xml ) Need Help??


in reply to Re^3: Grab input from the user and Open the file
in thread Grab input from the user and Open the file

Since I haven't explored modules, i used an if statement to match all possible URLs as shown below:

if (m/^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu +|gov|m +il|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\. +\,\;\?\'\\\+&%\$#\=~_\-]+))*$/){ my($host,$path) = ($4,$5); print "$host => $path\n"; }

I'm having the following error after testing

  • Unmatched ( in regex; marked by <-- HERE in m/^( <-- HERE ((ht|f)tp(s?))\:/ at challenge2.pl line 44.
  • Replies are listed 'Best First'.
    Re^5: Grab input from the user and Open the file
    by AnomalousMonk (Archbishop) on Nov 27, 2016 at 22:43 UTC
      if (m/^(((ht|f)tp(s?))\://)?(www.|[a-zA-Z].)[a-zA-Z0-9\-\.]+\.(com|edu +|gov|m +il|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\ +. +\,\;\?\'\\\+&amp;%\$#\=~_\-]+))*$/){ my($host,$path) = ($4,$5); print "$host => $path\n"; }

      Some thoughts:

      • You cannot use a  m// delimiter character (e.g.,  / forward slash) within a regex without escaping it. Your quoted regex
            m/^(((ht|f)tp(s?))\://)?...(/($|[a-z...]+))*$/
        has  / delimiter characters within it. I have rewritten the regex below with my favorite, balanced curlies, as delimiters.
      • The  /x regex modifier and whitespace are your friends (see Modifiers). As it stands, your regex is almost unreadable (at least by me) even if it were correct. Rewriting the regex as syntactically (but not necessarily semantically) correct:
        if (m{ ^ ( # open capturing group 1 (was unbalanced) ((ht|f)tp(s?) \: //)? # removed close paren after (s?) (www.|[a-zA-Z].) [a-zA-Z0-9\-\.]+ \. (com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk) (\:[0-9]+)* (/($|[a-zA-Z0-9\.\,\;\?\'\\\+&amp;%\$#\=~_\-]+))* ) $ # (maybe?) added for balance: close capture group 1 }x ) { my($host,$path) = ($4,$5); print "$host => $path\n"; }
        I can identify parts of this regex, but what, for instance, is  (www.|[a-zA-Z].) ('www' followed by any character, or else a single alpha character followed by any character) supposed to match in a URL? (This is immediately followed by  [a-zA-Z0-9\-\.]+ \. without any delimiter.)
      • In  (com|...|museum|us|ca|uk) the  us ca uk bit is suspicious. These are (I think) country codes, and should appear as part of a ccTLD like www.bbc.co.uk or www.what.ever.ac.ca and not on their own, as your regex allows. (Again, I'm sure CPAN has a module with regexes for matching URLs.)
      • Is  (/($|[a-zA-Z0-9\.\,\;\?\'\\\+&amp;%\$#\=~_\-]+))* really supposed to contain &amp;? (This may be an artifact of Perlmonks site rendering.)
      • Other parts I just can't figure out. (This may simply be due to ignorance on my part.)
      • A nit: Non-capturing groups (see  (?:pattern) in Extended Patterns in perlre) are your friends. Entirely too much stuff is captured unnecessarily in this regex for my taste.
      • A similar nit: Far too many characters are escaped unnecessarily; not every non-alphanumeric needs escaping.
      Bottom line: I doubt this regex would do what you intend even if it would compile (and the rewritten version is at least syntactically correct). Yet again: CPAN.


      Give a man a fish:  <%-{-{-{-<

    Re^5: Grab input from the user and Open the file
    by haukex (Archbishop) on Nov 28, 2016 at 10:38 UTC

      Hi valerydolce,

      Designing your own regex is certainly very good practice. For a production system I'd recommend existing modules, for example Regexp::Common to find URIs and URI to parse them. For example:

      use warnings; use strict; my $str = <<'END_STR'; I am an example http://www.perlmonks.org/?parent=1176663;node_id=3333 +text that contains <https://perlmonks.pair.com/?node_id=1176651> two URIs END_STR use Regexp::Common qw/URI/; use URI; while ($str=~/$RE{URI}{-keep}/g) { my $uri = URI->new($1); print "$uri\n"; print " Scheme: ", $uri->scheme, "\n"; print " Host: ", $uri->host, "\n"; print " Path: ", $uri->path, "\n"; print " Query: ", $uri->query, "\n"; }

      See the URI documentation for lots more ways to access the different parts of the URI. I did notice that unfortunately Regexp::Common apparently doesn't match the #fragment part of the URI, so here's an attempt at an alternate solution, using a regex based on the characters allowed in URIs from RFC 3986.

      # NOTE this is based on a quick skim of RFC 3986 and may not be comple +te! my $url_re = qr{ # https://tools.ietf.org/html/rfc3986#section-2 # URI = scheme ":" hier-part ...; hier-part = "//" ... # scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) [A-Za-z][A-Za-z0-9+\-.]* :// # gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" # sub-delims = "!" / "$" / "&" / "'" / "(" / ")" # / "*" / "+" / "," / ";" / "=" # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" ( [:/?#\[\]@!\$&'()*+,;=A-Za-z0-9\-._~] # pct-encoded = "%" HEXDIG HEXDIG | %[0-9A-Fa-f]{2} )* }x; while ($str=~/($url_re)/g) { my $uri = URI->new($1); print "$uri\n"; }

      Hope this helps,
      -- Hauke D

    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Domain Nodelet?
    Node Status?
    node history
    Node Type: note [id://1176663]
    help
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this?Last hourOther CB clients
    Other Users?
    Others meditating upon the Monastery: (4)
    As of 2024-04-19 14:09 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found