How to use perl to extract text between and look ahead and a look behind string without applying it twice?

Viewed 185

I currently have a string:

https://drive.google.com/file/d/j2903r293rj092j3r20/view?usp=sharing

I would like to extract j2903r293rj092j3r20 from. I am using a standard perl installation in Mac OS. I have

URL="https://drive.google.com/file/d/j2903r293rj092j3r20/view?usp=sharing"
echo $URL | perl -pe 's/https\:\/\/drive.google.com\/file\/d\///g' | perl -pe 's/\/view\?usp=sharing//g'

where I apply perl to the front and back. Is there a way to do this in one step instead? thanks

4 Answers

When parsing URLs you are probably better off using a proper parser, such as URI

use strict;
use warnings;
use URI;

my $uri = URI->new("https://drive.google.com/file/d/j2903r293rj092j3r20/view?usp=sharing");
my @path = $uri->path_segments;
print $path[-2];

This prints:

j2903r293rj092j3r20

I suppose if you need this in a one-liner it would be something like:

perl -MURI -lne'$u = URI->new($_); print (( $u->path_segments )[-2])'

Sure.

Firstly, using the substitution operator (s/.../.../) here is the wrong tool. You can use the match operator (m/.../) to just extract the bit of the string that you want.

echo $URL | perl -pe 'm/https\:\/\/drive.google.com\/file\/d\/(\w+)/ and $_ = $1'

Here, we're using "capturing parentheses" to copy the string of "word characters" (alphanumerics and the underscore) that follows the /d/ in the URL into the variable $1. We then copy that into $_ as that's the variable that -p will automatically print.

But we can do better than that. Both s/.../.../ and m/.../ allow us to change our delimiters, so that we don't have to escape all of those slashes.

echo $URL | perl -pe 'm[https://drive.google.com/file/d/(\w+)] and $_ = $1'

We can use print directly to remove the slightly confusing variable assignment at the end.

echo $URL | perl -ne 'print m[https://drive.google.com/file/d/(\w+)]'

And, if we know that our input data is always going to look like the current example, there's really no need to include so much of the URL.

echo $URL | perl -ne 'print m[/d/(\w+)]'

Update: You've got a comment suggesting that you use the URI module to parse your string. I'm not convinced that's particularly useful as the module will give you the path part of your URL and you still need to extract the correct part of the path. But, for completeness, here's an example using that module:

echo $URL | perl -MURI -ne 'print +(URI->new($_)->path_segments)[3]'

We create a URI object from our input and immediately call its path_segments() method to get the segments of the path. We print the fourth element of the list that is returned.

You can just put the two pieces comma separated in one perl -pe command:

echo $URL | perl -pe 's/https\:\/\/drive.google.com\/file\/d\///g','s/\/view\?usp=sharing//g'

Since you tagged the question with , I guess there is nothing wrong with a simple sed command like

echo "$s" | sed -n 's,.*/d/\([^/]*\).*,\1,p'

Match all up to and including /d/, capture the next characters until the first / or end of string and then match the rest. Replace with the contents of the first group and only print that value.

Related