开发者

How can I quote a long string in Perl?

开发者 https://www.devze.com 2023-01-15 21:19 出处:网络
I usually use simple quotes, but sometime I get very long lines which I can\'t break and also need to use escape characters, so I get something like this:

I usually use simple quotes, but sometime I get very long lines which I can't break and also need to use escape characters, so I get something like this:

my $str = "select query_accession,query_tag,hit_accession,hit_tag,significance from summaryTables where query_id = \'$query_id\';"

I know there are various other ways for representing strings in Perl. What would you recommend?

UPDATE Thank you all guys for the SQL-related suggestions. I learn some valuable stuff, but, my question remains (as a general one, regardless of SQL): is there some operator that allows quoting without catching line breaks?

what I do now is something开发者_Python百科 like:

my $str = "123 123 456 sdndfnd sdfdmd " .
 "dfsdjkfs 343489 dfjsdj 3 34kdfsk kd " .
 "fd kd9534 rfg 546 5";

which is quite ugly.


I like here documents, although some people despise them because the terminator has to appear at the beginning of the line despite your indent level.

my $str = <<"SQL";
  SELECT 
    query_accession,
    query_tag,
    hit_accession,
    hit_tag,
    significance
  FROM   
    summaryTables
  WHERE 
    query_id = ?
SQL

Perl v5.26 introduced indented here docs, like Ruby has. This looks almost the same, and if StackOverflow hasn't messed with the formatting, you should see that the final SQL marker is not flush left like the previous example:

my $str = <<~'SQL';
      SELECT 
        query_accession,
        query_tag,
        hit_accession,
        hit_tag,
        significance
      FROM   
        summaryTables
      WHERE 
        query_id = ?
    SQL

I also like formatting my SQL so I can easily see the structure in the statement, but that's a personal style. You might like something different.


No. All of Perl 5's string creation methods know about and include newlines. You can either use the concatenation operator as you did in your question, or abstract away the code needed to fix the problem:

#!/usr/bin/perl

use strict;
use warnings;

sub single_line {
    my @strings = @_;
    for (@strings) {
        s/\s+/ /g;
        s/^\s+|\s+$//g;
    }
    return wantarray ? @strings : $strings[0];
}


my $sql = single_line "
    select query_accession,query_tag,hit_accession,hit_tag,significance
    from summaryTables
    where query_id = ?;
";

print "[$sql]\n";


Look in perlop's Quote-Like Operators. Use qq for double quotes and q for single quotes.


As its SQL you're quoting then consider using something like SQL::Abstract to build your query.

For example:

use SQL::Abstract;

my $sql = SQL::Abstract->new;
my $query_id = 'xyzzy';  # arbitary value

my ($query, @bind) = $sql->select( 
    'summaryTables',
    [qw/ query_accession query_tag hit_accession hit_tag significance /],
    { query_id => $query_id },
);

This is what you would see in $query:

SELECT query_accession, query_tag, hit_accession, hit_tag, significance FROM summaryTables WHERE ( query_id = ? )

and in @bind:

xyzzy

So $query has already been built to accept SQL placeholder and @bind has the necessary values. So its then just usual DBI stuff like this to run the query:

my $sth = $dbh->prepare( $query );
$sth->execute( @bind );

Now you have all the safety and optimisation that SQL placeholders provide (see SQL injection Wikipedia entry)

Also see this previous SO question: Is there SQL parameter binding for arrays?

/I3az/


In the example that you have given, there is no reason not to break the line and there is no need to escape the single quotation marks.

my $str = "select query_accession,
                  query_tag,
                  hit_accession,
                  hit_tag,significance
           from   summaryTables
           where query_id = '$query_id';"

But, as others have pointed out, for substitutions in SQL queries that are going to be passed to DBI you're much better off using placeholders.


For general text building (re: your update) an exotic answer is to use a template engine. Its a bit like a printf on steroids!

Here is an example using Template Toolkit:

sub buildtt {
    use Template;
    my $tt = Template->new( START_TAG => '{', END_TAG => '}' );
    $tt->process( \$_[0], $_[1], \my $output );
    return $output;
}

my $str = buildtt '{a} {b} {c}' => {
    a => "123 123 456 sdndfnd sdfdmd",
    b => "dfsdjkfs 343489 dfjsdj 3 34kdfsk kd",
    c => "fd kd9534 rfg 546 5",
};

You can also build it like this:

my $str2 = buildtt '{all.join(" ")}' => {
    all => [ "123 123 456 sdndfnd sdfdmd",
             "dfsdjkfs 343489 dfjsdj 3 34kdfsk kd",
             "fd kd9534 rfg 546 5" ],
};

And here is an example with some quoting, etc:

my $str3 = buildtt '{all.join(" ")}' => {
    all => [ "no quoted text here",
             "here's some and here's some more",
             q{$str2 was "buildtt"},
             $str2 ],
};

A better example is something like this with your original SQL text:

my $sql = buildtt 'select {v.join(",")} from {t} where {q}' => { 
    v => [qw/ query_accession query_tag hit_accession hit_tag significance /],
    t   => 'summaryTables',
    q   => '( query_id = ? )',
};

Also see:

  • SO question: What should I use instead of printf in Perl?
  • String:TT CPAN module
  • List of template engines (not complete) on Perl5 wiki


And finally going from exotic to weird you could even create a new quote-like operator with PerlX::QuoteOperator:

use PerlX::QuoteOperator q_strip_newline => {
    -emulate => 'q',
    -with    => sub ($) {
        my $txt = shift;
        $txt =~ s/\n//g;
        $txt;
    },
};

my $str = q_strip_newline{123 123 456 sdndfnd sdfdmd
dfsdjkfs 343489 dfjsdj 3 34kdfsk kd
fd kd9534 rfg 546 5};

/I3az/


While there is no built in operator to do this, here's another approach that might work:

(my $str = qq(
123 123 456 sdndfnd sdfdmd 
dfsdjkfs 343489 dfjsdj 3 34kdfsk kd 
fd kd9534 rfg 546 5
)) =~ s/\n//g;

Or in two-step form:

my $str = qq(
123 123 456 sdndfnd sdfdmd 
dfsdjkfs 343489 dfjsdj 3 34kdfsk kd 
fd kd9534 rfg 546 5
);
$str =~ s/\n//g;

Both are ugly, but functional.


In this particular case I'd recommend using placeholders, unless you're absolutely 100% sure that $query_id can never contain "funny characters"

Obligatory xkcd reference

0

精彩评论

暂无评论...
验证码 换一张
取 消