Kramer
Kramer

Reputation: 13

Perl: Escape special chars in a string to match a regex

I'm writing bash functions to handle string operations with regexes. Bash built-in functions being very poor at the job, I'm using the perl command to do it.

For instance, here's my "strMatch" function (in bash):

# Usage: if (strMatch <string> <regex>); then...
function strMatch {
    local str="$1"
    local regex="$2"

    local perlCmd='if (qq('$str') =~ m/'$regex'/g) { print "0"; } else  { print "1"; }'
    return $(perl -e "$perlCmd")
}

Test string: foo-bar\rLoading... xx%\rFile: "some-(filename.ext".
regex: -bar(?:.*?)File: "(.\*?)\.ext"

Everything works fine except for one thing ; I can't find a way to properly escape special chars within the string to match (for some of them, at least).
I'm very new to Perl (except for regex syntax), so I tried various things found here and there without any success.

with 'qq' it doesn't handle '(', which is interpreted as a capturing group without a matching ')'. I'm guessing the same will happen with '['...
         => syntax error at -e line 1, near "qq(foo-bar\rLoading... xx%\rFile: "some-(filename.ext".) =~ m/-bar\r(?:.*?)File: "(.*?)\.ext"/g) { "
         => Can't find string terminator ")" anywhere before EOF at -e line 1.

with 'quotemeta' it's worse, breaks at ':', '%', '\r'... pretty much everything
         => Backslash found where operator expected at -e line 1, near "bar\"
         => Operator or semicolon missing before %

As a bonus, if I add 'w' or 'W' option to get perl warnings, it doesn't print anything!!! what's going on?

I just want the string to be able to contain pretty much anything including '%', '(', '[', '\r', '\n'... Anyone know how to do that??? What am I doing wrong ?

EDIT: Answered

Thank you choroba, using perl arguments $ARGV works like a charm. I also used a modified version of ikegami's solution which is more elegant.

Function now goes like this:

# Usage: if (strMatch <string> <regex>); then...
function strMatch {
    local str="$1"
    local regex="$2"

    local perlCmd='exit 1 if ($ARGV[0] !~ m/$ARGV[1]/g)'
    perl -e "$perlCmd" "--" "$str" "$regex"
    return $?
}

Edit2: Added "--" to stop processing options.

Upvotes: 1

Views: 1020

Answers (1)

choroba
choroba

Reputation: 241878

Pass the string and regex as parameters (I also simplified the Perl code):

#!/bin/bash
# Usage: if (strMatch <string> <regex>); then...
function strMatch () {
    local str="$1"
    local regex="$2"

    local perlCmd='print $ARGV[0] =~ m/$ARGV[1]/ ? 0 : 1'
    return $(perl -e "$perlCmd" "--" "$str" "$regex")
}

Tested with

~/test.sh $'foo-bar\rLoading... xx%\rFile: "some-(filename.ext"' '-bar(?:.*?)File: "(.*?).ext"'

Upvotes: 1

Related Questions