匹配perl中数字的最后一位数字

时间:2013-12-05 15:12:04

标签: regex perl

我有一个文件,里面有很多像这样提到的GUID

Dlg1={929EC5C7-0A40-4BE4-8F0A-60C3CB4A62A7}-SdWelcome-0

我想用已经使用工具生成的新GUID的最后8​​位替换这些GUID的最后8​​位数,到目前为止我尝试过的是

读取生成的GUID的最后8​​位数字,如此

$GUID=~/[0-9a-fA-F]{8}/;

将其分配给新变量,如

$newGUID =$1;

现在尝试将其替换为文件

中的旧GUID
if ($line =~/^.* {(.*)}/) {
  $line =~s/[0-9a-fA-F]{8}}/$newGUID/;
}

但它似乎没有工作,它用新的GUID的32位替换旧GUID的最后8​​位数,任何想法如何实现它。

3 个答案:

答案 0 :(得分:4)

  

它将旧GUID的最后8​​位替换为32位新GUID,任何想法如何实现它。

你现在有了这个:

$line =~s/[0-9a-fA-F]{8}}/$newGUID/;

您说用全部32位新GUID替换GUID的最后八个字符。这意味着你的发现和替换正确的角色,但是你用它替换它是错误的。

$newGUID等于什么?它是一个完整的32位GUID吗?如果是这样,你需要拉下最后8个字符。

我会推荐两件事。

  • 如果您在正则表达式中使用十六进制数字,请使用[[:xdigit:]]而不是[0-9a-fA-F]。虽然两者都非常相同。使用:xdigit:更清晰,更容易理解。
  • 在Perl中,我们喜欢正则表达式。哎呀,Perl正则表达式语法已经入侵并在几乎所有其他编程语言中找到了家。但是,正则表达式很难正确和测试。它们也很难理解。然而,除了正常表达之外,有时还有更好的方法可以做得更清楚,更容易理解。

在这种情况下,您应该使用substr而不是正则表达式。您确切地知道自己想要什么,并且知道字符串中的位置。 substr命令可以让您更容易理解,更清晰:

use constant {
    GUID_RE => qr/^[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}$/,
};

my $old_guid = '929EC5C7-0A40-4BE4-8F0A-60C3CB4A62A7';
my $new_guid = 'oooooooo-oooo-oooo-oooo-ooooXXXXXXXX';

# Regular expressions are great for verifying formats!
if ( not $old_guid =~ GUID_RE ) {
    die qq(Old GUID "$new_guid" is not a GUID string);
}

if ( not $new_guid =~ GUID_RE ) { # Yes, I know this will die in this case
    die qq(New GUID "$new_guid" is not a GUID string);
}

# Easy to understand, I'm removing the last eight characters of $old_guid
# and appending the last eight digits of $new_guid

my $munged_guid = substr( $old_guid, 0, -8 ) . substr( $new_guid, -8 );

say $munged_guid;  # Prints 929EC5C7-0A40-4BE4-8F0A-60C3XXXXXXX

我正在使用正则表达式来验证GUID格式是否正确,这对于正则表达式来说是一项很棒的任务。

我定义了一个GUID_RE常量。你可以查看它是如何定义的,并验证它是否是正确的格式(12个十六进制数字,4个十六进制数字,4个十六进制数字和12个十六进制数字全部用破折号分隔)。

然后,我可以在我的程序中使用GUID_RE常量,并且很容易看出我在做什么。我的GUID实际上是GUID_ID格式吗?

使用substr代替正则表达式可以轻松查看我正在做的事情。我将$old_guid中的最后八个字符移除,并附加$new_guid的最后八个字符。

同样,您的直接问题是您的s/.../.../找到了正确的字符,但您的替换字符串不正确。但是,这不是正则表达式的最佳用法。

答案 1 :(得分:3)

我认为你的问题是你没有正确地将$1设置为最后8位数(如果它来自该正则表达式,它将匹配前8位数并且不设置任何组)。你可以尝试$newGUID = substr($GUID, -8);之类的东西。我还认为$ GUIDTail之类的东西对变量更有意义,因为它不存储整个guid。

此外,目前你正在吃闭合的大括号。您应该在newGuid / guidTail中包含它,将其包含在s///调用中,或者将匹配中的卷曲更改为(?=\})(表示匹配此但不包括在匹配中)。

P.S。你假设那里只有一个guid就行了。如果有多个guid的可能性(或以其他方式消除你想要修改的那个,那么你可能想要为匹配添加一个全局修饰符,但这只会替换第一个)。

答案 2 :(得分:2)

这是一个小代码片段,演示了我认为你所遵循的原则。首先,我从一个给定的字符串开始,然后取出它的最后8个字符并将其存储在一个新变量$insert中。然后我对输入数据执行一些严格的替换(这里是内部文件句柄DATA,这在演示时很方便),并打印更改后的字符串。

替换中的正则表达式查找大括号{ ... },其中包含十六进制数字[:xdigit:]和短划线\-[[:xdigit:]\-]+),后跟八位十六进制数字。 \K转义允许我们在其之前“保留”匹配的字符串,因此我们需要做的就是插入我们存储的字符串,并替换结束的大括号。

如果您希望在文件上尝试此操作,请将<DATA>更改为<>并按以下方式运行:

perl script.pl input 

<强>代码:

use strict;
use warnings;

my $new = "929EC5C7-0A40-4BE4-8F0A-1234567890";
my $insert = substr($new, -8);

while (<DATA>) {
    s/\{[[:xdigit:]\-]+\K[[:xdigit:]]{8}\}/$insert}/i;
    print;
}

__DATA__
Dlg1={929EC5C7-0A40-4BE4-8F0A-60C3CB4A62A7}-SdWelcome-0

<强>输出:

Dlg1={929EC5C7-0A40-4BE4-8F0A-60C334567890}-SdWelcome-0