如何提取 SQL 语句的一部分以进行搜索和替换?

如何提取 SQL 语句的一部分以进行搜索和替换?

我正在使用 bash shell 尝试进行搜索和替换。我有一个看起来像这样的行文件

...
INSERT INTO currency (name, code, symbol) VALUES ('Baht', 'THB', '฿');
...

我想将每一行转换为

currency = Currency.find_by_iso('THB') || Currency.new(:code => 'THB')

如您所见,我从 INSERT SQL 命令中提取了第二个参数。我以为我能做到

perl -w -pe "s/INSERT INTO currency (name, code, symbol) VALUES ('(.*?)', '(.*?)', '(.*?)');/currency = Currency.find_by_iso(\$&) || Currency.new(:code => '\$&')/" currencies.rb

但什么也没发生——也就是说,替换的输出使线路保持不变。如何从 SQL 语句中捕获第二个值并从中创建新行?

答案1

替换的输出使行保持不变

这表明您的正则表达式与输入不匹配,因此让我们退后一步,看看是否可以获得有效的最小正则表达式:

perl -w -pe "s/INSERT INTO currency (name, code, symbol) VALUES ('(.*?)', '(.*?)', '(.*?)');//" currencies.rb
> INSERT INTO currency (name, code, symbol) VALUES ('Baht', 'THB', '?');

只需删除替换件,毫不奇怪,与您最初得到的没有任何区别,它与输入不匹配。

现在,正则表达式的最后一部分('(.*?)', '(.*?)', '(.*?)')包含了在正则表达式中具有特殊含义的字符分配,因此让我们删除它们并看看是否有效:

perl -w -pe "s/INSERT INTO currency (name, code, symbol) VALUES .*;//" currencies.rb
> INSERT INTO currency (name, code, symbol) VALUES ('Baht', 'THB', '?');

仍然不匹配,现在唯一的特殊字符是()可能应该转义的:

perl -w -pe "s/INSERT INTO currency \(name, code, symbol\) VALUES .*;//" currencies.rb
> 

是的,匹配 - 我们的输入已匹配并删除,所以让我们再次添加末尾位,这次也转义其他()s:

perl -w -pe "s/INSERT INTO currency \(name, code, symbol\) VALUES \('(.*?)', '(.*?)', '(.*?)'\);//" currencies.rb
> 

仍然匹配,所以让我们再次添加替换:

perl -w -pe "s/INSERT INTO currency \(name, code, symbol\) VALUES \('(.*?)', '(.*?)', '(.*?)'\);/currency = Currency.find_by_iso(\$&) || Currency.new(:code => '\$&')/" currencies.rb
> currency = Currency.find_by_iso(INSERT INTO currency (name, code, symbol) VALUES ('Baht', 'THB', '?');) || Currency.new(:code => 'INSERT INTO currency (name, code, symbol) VALUES ('Baht', 'THB', '?');')

嗯,似乎匹配错误的部分。这是因为 & 被整个匹配表达式替换,而不是您想要的单个子组$1$2等等:

perl -w -pe "s/INSERT INTO currency \(name, code, symbol\) VALUES \('(.*?)', '(.*?)', '(.*?)'\);/currency = Currency.find_by_iso(\$2) || Currency.new(:code => '\$2')/" currencies.rb
> currency = Currency.find_by_iso(THB) || Currency.new(:code => 'THB')

快到了,缺少一些引号 - 我们也不需要其他两个子组匹配,所以让我们删除它们:

perl -w -pe "s/INSERT INTO currency \(name, code, symbol\) VALUES \('.*?', '(.*?)', '.*?'\);/currency = Currency.find_by_iso('\$1') || Currency.new(:code => '\$1')/" currencies.rb 
> currency = Currency.find_by_iso('THB') || Currency.new(:code => 'THB')

就这样,正是我们想要的。

当面对似乎不起作用的复杂正则表达式时,通常是一些特殊字符的问题,它因语言和工具的不同而不同——有时需要转义,有时则不需要。首先用更简单的替代方案删除这些字符总是有帮助的,直到你得到一个与你的输入部分匹配的正则表达式,即使它不完全是你想要的部分 - 然后将它从那里一点一点地扩展出来,直到它中断或你会得到你想要的。如果您发现它打破了这一点,您应该阅读您正在使用的语言/工具的文档,以找出您实际正在寻找的语法。

相关内容