Regex 什么是让我得到一张照片的正确方法?

Regex 什么是让我得到一张照片的正确方法?,regex,perl,unicode,grapheme,Regex,Perl,Unicode,Grapheme,为什么打印的是U,而不是Ü #!/usr/bin/env perl use warnings; use 5.014; use utf8; binmode STDOUT, ':utf8'; use charnames qw(:full); my $string = "\N{LATIN CAPITAL LETTER U}\N{COMBINING DIAERESIS}"; while ( $string =~ /(\X)/g ) { say $1; } # Output: U

为什么打印的是
U
,而不是
Ü

#!/usr/bin/env perl
use warnings;
use 5.014;
use utf8;
binmode STDOUT, ':utf8';
use charnames qw(:full);

my $string = "\N{LATIN CAPITAL LETTER U}\N{COMBINING DIAERESIS}";

while ( $string =~ /(\X)/g ) {
        say $1;
}

# Output: U

这对我来说是可行的,尽管我在ubuntu上有一个较旧版本的perl,
5.012
。我对脚本的唯一更改是:
使用5.012

$ perl so.pl 
Ü

我可以说输出不正确吗?检查很容易:将循环代码替换为:

my $counter;
while ( $string =~ /(\X)/g ) {
  say ++$counter, ': ', $1;
}
。。。并查看正则表达式将匹配多少次。我猜它只会匹配一次

或者,您可以使用以下代码:

use Encode;
sub codepoint_hex {
    sprintf "%04x", ord Encode::decode("UTF-8", shift);
}
。。。然后在while循环中打印codepoint_hex($1),而不是普通的$1。

1)显然,您的终端无法显示扩展字符。在我的终端上,它打印:

2)
\X
不会做你认为它会做的事。它只选择组合在一起的字符。如果使用字符串
“fu\N{combing DIAERESIS}r”
,程序将显示:

f
u¨
r
f
ü
r
请注意,变音符号不是单独打印的,而是与其对应的字符一起打印的

3)要将所有相关字符合并为一个字符,请使用模块:

它显示:

f
u¨
r
f
ü
r
你的代码是正确的

你真的需要根据数字来处理这些事情;不要相信“终端”显示的内容。通过管道,可能使用
-x
-v
,查看它真正在做什么

眼睛是骗人的,节目更糟。你的终端程序有缺陷,对你撒谎也是。正常化不重要

$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say "crème brûlée"'
crème brûlée
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say "crème brûlée"' | uniquote -x
cr\x{E8}me br\x{FB}l\x{E9}e
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFD "crème brûlée"' 
crème brûlée
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFD "crème brûlée"' | uniquote -x
cre\x{300}me bru\x{302}le\x{301}e

$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFC scalar reverse NFD "crème brûlée"' 
éel̂urb em̀erc
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say NFC scalar reverse NFD "crème brûlée")' | uniquote -x
\x{E9}el\x{302}urb em\x{300}erc
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say scalar reverse NFD "crème brûlée"'
éel̂urb em̀erc
$ perl -CS -Mutf8 -MUnicode::Normalize -E 'say scalar reverse NFD "crème brûlée"' | uniquote -x
e\x{301}el\x{302}urb em\x{300}erc

它在Perl5.12上运行。您需要按数字播放这些内容;不要相信“终端”显示的内容。通过管道,可能使用
-x
-v
,查看它真正在做什么。眼睛是骗人的,节目更糟。您的终端程序有缺陷,所以我在对您撒谎。我正在阅读手册并记住了这个问题,这里有关于\X的更多信息:
perldoc perlrebackslash
。首先:NFC不是这样做的。这里正好如此。它做许多其他的事情;人们误解了它的一般用途和用途。第二:如果您的终端程序不能正确显示组合字符,它将以不同的方式处理规范等效序列,这是邪恶和错误的。参见Unicode标准第60页的一致性要求C6。你的是错误的:你不应该欺骗它,否则你就不能写:
perl-CS-Mutf8-MUnicode::Normalize-E'say scalar reverse NFD(“crème brèléE”)”
=>
Éel̂urb em̀erc.你认为他认为
\X
做什么?@tchrist I.是的,你是对的。我的终端机和OP的终端机一样笨重,但原因不同。它应该结合变音符号本身。但我相信规范化可以用于在不完全符合unicode的终端上显示扩展字符。二,。我不确定我是否真的理解你关于NFC的观点。因为字符是颠倒的,所以重音都是错的。这并不奇怪。三、
\X
匹配一个字符及其所有后续的变音符号。我错了吗?我不知道什么是“扩展字符”。使用扩展字符而不是下行字符?我对NFC的看法是,它的主要工作是以可预测的顺序呈现变音符号:因此是规范的。碰巧的是,只有很少几个字符,它选择了一个预合成的字符。是的,在你的情况下是这样的。但是只有很少的compat字形,并且有无限的字形。如果我在一个基本字母上有一个下划线、一个宏符和一个波浪号,它就不能将这三个标记组合成一个预合成的代码点,因为根本没有这样的东西。正常化也会杀死单体,顺便说一句,使用5.010;他也做这项工作。使用perl 5.012在Ubuntu上测试;它与KDE的
Konsole
(2.7.2)不兼容。现在我用
xterm
试过了,它成功了。tchrist,别再教我这个建议了!在Encode库中使用隐式编码比显式编码更容易产生错误代码,在最坏的情况下产生不安全代码。假设
-Mstrictures-Mautodie=:所有
w/示例
perl-CD-E'openmy$fh,“@tchrist,有很多理由使用
decode
encode
。我们中的许多人在文本文件句柄以外的地方获得输入。我同意
decode
在这里毫无意义(因为匹配首先需要解码文本才能工作)。应该是
sprintf”%04x“,ord shift
@daxim我对此没有任何意义。关键是所有编码相同的流都不需要手动编码/解码。@ikegami是的,你说得对:有。它们只是不包括所有编码都相同的流,几乎每一个编码都是相同的。数据库和环境变量,加上程序参数,是您经常需要处理编码/解码的地方。我已经看到太多的程序在流上不恰当地使用它们,因此我开始将其视为一种反模式。在一个完美的世界中,应该也会这样做,但Perl并不完美。隐式解码功能(
-C
开关,
使用open
pragma,
open()
带层)不会抛出异常,即使在致命警告生效的情况下(如果您没有从上面识别它,pragma
Structures
也会抛出异常)
perldoc PerlIO::encoding
表示添加
$PerlIO::encoding::fallback=Encode::FB_CROAK
会使它们致命,但实际上没有帮助。(现在5.16的代码已经冻结,我们可能要等一年才能修复所有这些混乱。)目前只有编码库DTRT。我同意。无需对代码进行任何更改。这是OP终端的问题(我的也是,Debian的KDE的
konsole
)。