我正在使用Perl 5.16.2来计算$_
字符串中特定分隔符的出现次数。分隔符通过@ARGV
数组传递给我的Perl程序。我在程序中验证它是否正确。我计算字符串中分隔符数量的指令是:
$dlm_count = tr/$dlm//;
如果我对分隔符进行硬编码,例如$dlm_count = tr/,//;
计数正确。但是当我使用变量$ dlm时,计数是错误的。我修改了说明
$dlm_count = tr/$dlm/\t/;
并实现了如何在字符串中插入选项卡,该操作替换了四个字符“$
”,“d
”,“l
”中的任何一个的每个实例。或“m
”到\t
- 即组成我的变量名称$dlm
的四个字符中的任何一个。
这是一个说明问题的示例程序:
$_ = "abcdefghij,klm,nopqrstuvwxyz";
my $dlm = ",";
my $dlm_count = tr/$dlm/\t/;
print "The count is $dlm_count\n";
print "The modified string is $_\n";
$_
字符串中只有两个逗号,但此程序打印以下内容:
The count is 3
The modified string is abc efghij,k ,nopqrstuvwxyz
为什么$dlm
标记被视为四个字符的文字字符串而不是变量名?
答案 0 :(得分:3)
在docs on perlop 'Quote Like Operators'的部分中,它指出:
因为音译表是在编译时构建的,所以也不是 SEARCHLIST和REPLACEMENTLIST受到双重报价 插值。这意味着如果你想使用变量,你必须 使用eval():
答案 1 :(得分:3)
你不能以tr
方式使用它,它不会插入变量。它通过字符替换严格执行。所以这个
$string =~ tr/a$v/123/
将使用a
替换每个1
,将$
替换为2
,将每个v
替换为3
。它不是正则表达式而是音译。来自perlop
由于音译表是在编译时构建的,因此SEARCHLIST和REPLACEMENTLIST都不会进行双引号插值。这意味着如果要使用变量,则必须使用eval():
eval "tr/$oldlist/$newlist/"; die $@ if $@; eval "tr/$oldlist/$newlist/, 1" or die $@;
上述文档示例提示如何计算。对于$dlm
$string
$dlm_count = eval "\$string =~ tr/$dlm//";
$string
已转义,因此在到达eval
之前不会进行插值。在你的情况下
$dlm_count = eval "tr/$dlm//";
您还可以使用tr
(或正则表达式)以外的工具。例如,字符串位于$_
my $dlm_count = grep { /$dlm/ } split //;
当split
以空字符串($_
)的模式中断//
时,它会返回其中所有字符的列表。然后,grep
块会针对$dlm
对每个$dlm
进行测试,因此会返回$_
中$dlm_count
个$dlm
个字符的列表。由于这被分配给标量,class Something {
public:
void start() {
this->task_ = std::thread(&Something::someTask, this);
// this->task_.detach(); <<<<<< Don't do that.
}
void stop() {
this->isRunning_ = false;
task_.join(); // <<< Instead of detaching the thread, join() it.
}
~Something() {
this->stop();
}
private:
std::atomic<bool> isRunning_;
std::thread task_;
void someTask()
{
this->isRunning_ = true;
while(this->isRunning_) {
// do something forever
}
}
};
被设置为该列表的长度,这是所有std::thread
的计数。
答案 2 :(得分:2)
正如文档和您发现的那样,tr///
没有内插。简单的解决方案是使用s///
代替。
my $dlm = ",";
$_ = "abcdefghij,klm,nopqrstuvwxyz";
my $dlm_count = s/\Q$dlm/\t/g;
如果在循环中执行音译,以下内容可能会显着加快速度:
my $dlm = ",";
my $tr = eval "sub { tr/\Q$dlm\E/\\t/ }";
for (...) {
my $dlm_count = $tr->();
...
}
答案 3 :(得分:1)
尽管有几个答案暗示了eval()
tr///
的成语,但没有一个能够涵盖字符串中包含tr
个语法字符的情况,例如 - (连字符):
$_ = "abcdefghij,klm,nopqrstuvwxyz";
my $dlm = ",";
my $dlm_count = eval sprintf "tr/%s/%s/", map quotemeta, $dlm, "\t";
但正如其他人所指出的那样,有很多方法可以计算Perl中避免eval()
的字符,这是另一种:
my $dlm_count = () = m/$dlm/go;