我该如何在Perl中引用一个长字符串?

8

我通常使用简单引号,但有时我会遇到很长的行而无法换行,还需要使用转义字符,所以我得到了类似于这样的内容:

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

我知道在Perl中有各种表示字符串的方式。你会推荐哪种?

更新 感谢大家提供与SQL相关的建议。我学到了一些有价值的东西,但是,我的问题仍然存在(作为一个普遍的问题,不考虑SQL):是否有某个运算符允许在不捕获换行符的情况下引用?

现在我做的事情类似于:

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

这看起来相当丑陋。


请查看http://www.perlmonks.org/?node_id=401006。 - Nikhil Jain
cough 注入漏洞 cough http://xkcd.com/327/ - Ether
8个回答

9

我喜欢这里的文档,尽管有些人鄙视它们,因为终止符必须出现在行的开头,而不管您的缩进水平。

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

Perl v5.26引入了这种缩进的文档,类似于Ruby。这看起来几乎一样,如果StackOverflow没有搞糟格式,你应该能看到最后的SQL标记不像前面的例子一样靠左对齐:
my $str = <<~'SQL';
      SELECT 
        query_accession,
        query_tag,
        hit_accession,
        hit_tag,
        significance
      FROM   
        summaryTables
      WHERE 
        query_id = ?
    SQL

我也喜欢格式化我的SQL语句,这样我就可以轻松地看到语句中的结构,但这是个人的风格。你可能喜欢不同的东西。

4

4

不需要。Perl 5的所有字符串创建方法都知道并包含换行符。你可以像在问题中所做的那样使用连接运算符,或者抽象出需要修复问题的代码:

#!/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";

3
作为你引用的SQL,考虑使用类似 SQL::Abstract 的工具来构建查询语句。
例如:
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 },
);

这是您在$query中看到的内容:

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

并且在@bind中:

xyzzy

因此,$query 已经被构建为接受 SQL 占位符,并且 @bind 具有必要的值。因此,只需像这样运行查询的通常 DBI 的内容:

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

现在您已经拥有了SQL占位符提供的所有安全性和优化功能(请参见SQL注入维基百科条目
还可以参考之前的SO问题:是否有适用于数组的SQL参数绑定? /I3az/

1
在这种特定情况下,我建议使用占位符,除非您绝对100%确定$query_id永远不会包含“有趣的字符”。

义务xkcd参考


你是否可以详细说明一下什么是“占位符”? - David B
2
@David B 即使你认为你非常确定,也还是可以使用占位符。请参考DBI中的占位符是什么,为什么要使用它们? - Greg Bacon

1

虽然没有内置的运算符可以实现这一点,但这里有另一种可能有效的方法:

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

或者以两步形式:

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

两者都不好看,但很实用。


1
在您提供的示例中,没有理由不换行,也没有必要转义单引号。
my $str = "select query_accession,
                  query_tag,
                  hit_accession,
                  hit_tag,significance
           from   summaryTables
           where query_id = '$query_id';"

但是,正如其他人指出的那样,对于将要传递给DBI的SQL查询中的替换,最好使用占位符。


3
你不应该提供一个危险的错误示例。从一开始就使用占位符展示正确的方法,否则有人会复制/粘贴它,并且看到它“运作正常”,并感到满意。 - Christoffer Hammarström

1

对于一般的文本构建(关于您的更新),使用模板引擎是一个异乎寻常的答案。它有点像类似于 printf 的强化版!

以下是使用 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",
};

你也可以这样构建:

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

这里有一个带引用等的示例:

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

一个更好的例子是使用你原始的SQL文本,像这样:
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 = ? )',
};

另请参阅:


最后,您甚至可以使用类似引用的运算符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/


非常感谢您。同时,也要感谢您激发了我写了两个(或者是三个!)答案!(特别是让我吹响了我的 PerlX::QuoteOperator 小号 :)) - draegtun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接