【问题标题】:Unable to match Indian Rupee currency symbol using regex in Perl无法在 Perl 中使用正则表达式匹配印度卢比货币符号
【发布时间】:2015-12-06 17:22:27
【问题描述】:

以下是我的文字:

Total: ₹ 131.84

Thanks for choosing Uber, Pradeep

我想匹配金额部分,使用以下代码:

if ( $mail_body =~ /Total: \x{20B9} (\d+)/ ) {
    $amount = $1;
}

但是,它不匹配,尝试使用正则表达式调试,这是输出:

Compiling REx "Total: \x{20B9} (\d+)"
Final program:
   1: EXACT <Total: \x{20b9} > (5)
   5: OPEN1 (7)
   7:   PLUS (9)
   8:     DIGIT (0)
   9: CLOSE1 (11)
  11: END (0)
anchored utf8 "Total: %x{20b9} " at 0 (checking anchored) minlen 10
Matching REx "Total: \x{20B9} (\d+)" against "Total: %342%202%271%302%240131.84%n%nThanks for choosing Ube"...
UTF-8 pattern...
Match failed
Freeing REx: "Total: \x{20B9} (\d+)"

完整代码在http://pastebin.com/TGdFX7hg

【问题讨论】:

  • 如果你输出$mail_body会是什么样子?
  • 这里显示匹配:regex101.com/r/iO5aL8/2
  • @karthikmanchala 我知道。但它是兼容的。不一样。
  • 其实可以用/Total:\s+\xE2\x82\xB9\s+(\d+)/
  • %342%202%271%302%240 转换为 e2 82 b9 c2 a0,所以 @stribizhev 的方法应该有效。旁注: (\d+(.\d*)?) 还捕获逗号后面的部分。

标签: regex perl unicode


【解决方案1】:

免责声明:这感觉更像是评论而不是答案,但我需要更多空间。

我以前从未使用过MIME::Parser 和朋友,但根据我在文档中阅读的内容,以下可能有效:

use Encode qw(decode);

# according to your code, $text_mail is a MIME::Entity object
my $charset = $text_mail->head->mime_attr('content-type.charset');
my $mail_body_raw = $text_mail->bodyhandle->as_string;

my $mail_body = decode $charset, $mail_body_raw;

想法是从MIME::Head 对象中获取字符集,然后使用Encode 对正文进行相应的解码。

当然,如果您知道它始终是 UTF-8 文本,您也可以对其进行硬编码:

my $mail_body = decode 'UTF-8', $mail_body_raw;

之后,您的正则表达式可能仍然无法工作,因为根据您问题中的调试输出,₹和数字之间的字符实际上不是简单的空格(ASCII 32,U+0020),而是不间断的空格(U+00A0)。您应该可以将其与\s 匹配:

if ( $mail_body =~ /Total: \x{20B9}\s(\d+)/ ) {

【讨论】:

  • 感谢@melpomene 使用了 decode 子程序并使用了这个 "$mail_body =~ /Total: \x{20B9}(?:\x{00A0}|\x{C2A0}|\s) (\d+(.\d*)?)/" 有效!
【解决方案2】:

这是在寻找解释,而不是直接的答案。请多多包涵。


我相信您的$mail_body 不包含您认为的内容。您将输入数据发布为纯文本。是从邮件客户端复制的吗?

如果我从问题中获取代码和输入数据并使用use re 'debug' 运行它,我会得到不同的输出。

use utf8;
use strict;
use warnings;
use re 'debug';

my $mail_body = qq{Total: ₹ 131.84

Thanks for choosing Uber, Pradeep};

if ( $mail_body =~ /Total: \x{20B9} (\d+)/ ) {
    my $amount = $1;
}

它会产生这个:

Compiling REx "Total: \x{20B9} (\d+)"
Final program:
   1: EXACT <Total: \x{20b9} > (5)
   5: OPEN1 (7)
   7:   PLUS (9)
   8:     POSIXU[\d] (0)
   9: CLOSE1 (11)
  11: END (0)
anchored utf8 "Total: %x{20b9} " at 0 (checking anchored) minlen 10 
Matching REx "Total: \x{20B9} (\d+)" against "Total: %x{20b9} 131.84%n%nThanks for choosing Uber, Pradeep"
UTF-8 pattern and string...
Intuit: trying to determine minimum start position...
  Found anchored substr "Total: %x{20b9} " at offset 0...
  (multiline anchor test skipped)
Intuit: Successfully guessed: match at offset 0
   0 <> <Total: >            |  1:EXACT <Total: \x{20b9} >(5)
  11 < %x{20b9} > <131.84%n%n>|  5:OPEN1(7)
  11 < %x{20b9} > <131.84%n%n>|  7:PLUS(9)
                                  POSIXU[\d] can match 3 times out of 2147483647...
  14 <%x{20b9} 131> <.84%n%nTha>|  9:  CLOSE1(11)
  14 <%x{20b9} 131> <.84%n%nTha>| 11:  END(0)
Match successful!
Freeing REx: "Total: \x{20B9} (\d+)"

让我们将带有 Matching REx 的行与您的输出进行比较:

against against "Total: %x{20b9} 131.84%n%nThanks for choosing Uber, Pradeep"
against "Total: %342%202%271%302%240131.84%n%nThanks for choosing Ube"...

我们可以看到,我的输出有 %x{e2} 等等,而你的输出有 %342

当我开始尝试这段代码时,我忘记在我的代码中输入use utf8,所以当正则表达式引擎尝试匹配时,我得到了一堆单个字符:

%x{e2}%x{82}%x{b9}

然后它拒绝了匹配。

所以我的结论是:Perl 不知道你的输入数据是 utf8。

【讨论】:

  • 是的,问题是无论数据来自哪里,它都没有被解码(所以仍然是一堆字节,而不是 unicode 文本)。
  • 谢谢,我该如何解决这个问题?
  • @Pradeep 您的文字 ($mail_body) 来自哪里?
  • @Pradeep:你可以看看这个模块,尝试找到当前编码:perldoc.perl.org/Encode/Guess.html并将其转换为utf8
  • @CasimiretHippolyte Ew。如果可以避免,永远不要猜测编码。
猜你喜欢
  • 1970-01-01
  • 2015-07-24
  • 2017-09-20
  • 2013-10-16
  • 2021-09-06
  • 2015-02-24
  • 2011-11-15
  • 1970-01-01
  • 2014-11-16
相关资源
最近更新 更多