简体   繁体   English

Perl的。 同时匹配和替换

[英]Perl. Simultaneous match and substitution

Im trying to find specific pattern and do substitution in it. 我试图找到特定的模式并在其中进行替换。 And assign result to another variable. 并将结果分配给另一个变量。

For example: I have a variable $text with some text in which Im trying to find pattern like "Date:\\s+\\d{4}.\\d\\d.\\d\\d", substitute dots for dashes in it and then assign result to $result. 例如:我有一个带有文本的变量$ text,我试图在其中查找诸如“ Date:\\ s + \\ d {4}。\\ d \\ d。\\ d \\ d”之类的模式,用点号代替破折号,然后将结果分配给$ result。

This version works: 此版本适用:

($result) = $text =~ /Date:\s+(\d{4}\.\d\d\.\d\d)/igs;
 $result =~ s/\./-/g;

But Im trying to do it in one operation. 但是我试图通过一项手术做到这一点。 Something like: 就像是:

($result) = $text =~ s/Date:\s+(\d{4})\.(\d\d)\.(\d\d)/$1-$2-$3/igs;

But it gives me result "1". 但这给了我结果“ 1”。 So, the question is: Is it possible to do such thing in one operation? 因此,问题是:是否可以在一个操作中执行此操作? Or what is the best option to do it and minimize code? 还是最好的选择是这样做并最小化代码?

my $result;
$text =~ s/Date:\s+(\d{4})\.(\d\d)\.(\d\d)/ $result= "$1-$2-$3" /ei;

If you move the parentheses around so that $text is first assigned to $result , you can then make the substitution apply to $result instead of $text , and so you can strip all the excess text you do not want, and use your original idea of building the date with dashes - instead of dots: 如果移动括号,以便首先将$text分配给$result ,则可以将替换应用于$result而不是$text ,这样就可以去除所有不需要的多余文本,并使用原始文本建设有破折号日期的想法-而不是点:

(my $result = $text) =~ s/.*Date:\s+(\d{4})\.(\d\d)\.(\d\d).*/$1-$2-$3/igs;

Note the use of .* at start and end of string, which will consume all of the text, so the only thing left is the date. 请注意,在字符串的开头和结尾使用.* ,这将占用所有文本,因此剩下的唯一内容就是日期。 This line of code is really two operations in one, like so: 这行代码实际上是两个操作合而为一,如下所示:

my $result = $text;
$result =~ s/..../;

Another version is to use a post-script for loop, which will make use of the fact that $_ is aliased to the list arguments: 另一个版本是使用后脚本for循环,它将利用$_别名为list参数这一事实:

tr/./-/ for ((my $result) = $text =~ /Date:\s+([\d.]+)/);

This will assign the date to $result , and then pass $result to the argument list in for , applying the transliteration to it. 这会将日期分配给$result ,然后将$result传递给for的参数列表,对其应用音译。 It affects the real variable $result because $_ is aliased within the loop. 它会影响实变量$result因为$_在循环中具有别名。

Also note that this is really an academic question, in my opinion. 另外请注意,我认为这确实是一个学术问题。 I would not recommend using this in production code, and your original is far better and more readable. 我不建议在生产代码中使用它,并且您的原始版本要好得多且可读性强。 Although I would use transliteration instead of a substitution: 尽管我将使用音译而不是替换:

$result =~ tr/./-/;

请尝试一下($ result = $ text)=〜s / Date:\\ s +(\\ d {4})。(\\ d \\ d)。(\\ d \\ d)/ $ 1- $ 2- $ 3 / igs

You shouldn't be too keen on writing multiple operations into a single statement: it only serves to spoil the readability of your code. 您不应该太热衷于在单个语句中编写多个操作:它只会破坏代码的可读性。 But I suggest that you write something like this. 但是我建议你写这样的东西。

There is no point in using the /s modifier on your original pattern match as it affects only the . 在原始模式匹配项上使用/s修饰符没有意义,因为它仅影响. metacharacter, and there are none of these in your pattern. 元字符,并且您的模式中没有这些字符。 Also, it makes no sense to use /g as you are interested only in a single match. 另外,使用/g没有意义,因为您只对单个匹配感兴趣。

Don't be tempted to join the two statements into one line, as the if statement modifier would then also apply to the my declaration which has some very strange effects. 不要试图将两个语句合并为一行,因为if语句修饰符也将应用于my声明,这会产生非常奇怪的效果。

use strict;
use warnings;
use 5.010;

my $text = 'Date: 1994.04.04';

my $result;
$result = $1 =~ tr/./-/r if $text =~ /Date:\s+(\d{4}\.\d\d\.\d\d)/i;

say $text;
say $result;

output 产量

Date: 1994.04.04
1994-04-04

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM