【问题标题】:Trim unicode whitespace in PHP 5.2在 PHP 5.2 中修剪 unicode 空格
【发布时间】:2010-11-12 16:36:51
【问题描述】:

如何修剪string(6) " page",其中第一个空格是 0xc2a0 不间断空格?

我试过trim()preg_match('/^\s*(.*)\s*$/u', $key, $m);

另一个问题:如何可靠地复制这些字符?它们似乎被转换为“正常”空间,这使得调试变得困难。

【问题讨论】:

  • “复制”是什么意思?从哪里复制什么?从网页到 IDE/编辑器?
  • @antil 我会从浏览器说。我有类似的问题,chrome、firefox 等,只是在 utf-8 和 ISO-8859-1 中显示为空格

标签: php unicode utf-8 whitespace character-properties


【解决方案1】:
preg_replace('/^[\pZ\pC]+|[\pZ\pC]+$/u','',$str);

【讨论】:

  • 可悲的是,在我找到你的答案之前,我自己找到了。但是您忘记了 u 修饰符,并且 s 没有什么意义。工作代码:preg_replace('/^\p{Z}+|\p{Z}+$/u', '', $key).
  • 更新为preg_replace('/^[\pZ\pC]+|[\pZ\pC]+$/u'
  • @Znarkus:PHP 是否不支持或至少不鼓励通过/x(?x) 在正则表达式上使用非疯狂模式?
  • 如果我想删除所有的空格,我是否还需要调用 trim 或者这样就足够了?
  • @Adam:表达式将修剪所有前导/尾随空格,而不需要 trim()。
【解决方案2】:

PCRE unicode properties 属性可以用来实现这个

这是我玩过的代码,似乎可以满足您的要求:

<?php
function unicode_trim ($str) {
    return preg_replace('/^[\pZ\pC]+([\PZ\PC]*)[\pZ\pC]+$/u', '$1', $str);
}

$key = chr(0xc2) . chr(0xa0) . '#page#' . chr(0xc2) . chr(0xa0);

var_dump(unicode_trim($key));

结果

[~]> php e.php
string(6) "#page#"

解释:

\p{xx} 具有 xx 属性的字符 \P{xx} 没有 xx 属性的字符

如果 xx 只有一个字符,则可以删除 {},例如\p{Z} 与 \pZ

相同

Z 代表所有分隔符,C 代表所有“其他”字符(例如控制字符)

【讨论】:

  • 这将删除任何非字母字符 (#!%123...)。
  • 没有去掉哪个尾随字符?它肯定会去除尾随 0xc2a0 - 正如您从我上面粘贴的输出中看到的那样。但是我已经更新了几次正则表达式,所以也许你尝试过之前的。
  • 普通空格,以为是最新版本。非常感谢,非常有帮助!
  • @Anti Veeranna:PHP 使用哪个版本的 PCRE?我觉得它有点落后,但我可能错了。
【解决方案3】:

现有解决方案仅提及 \pZ 字符。但是,有六个 Unicode 空白字符不在该属性的范围内:

% unichars '\p{WhiteSpace}' '\PZ'
 --    9 0009 CHARACTER TABULATION
 --   10 000A LINE FEED (LF)
 --   11 000B LINE TABULATION
 --   12 000C FORM FEED (FF)
 --   13 000D CARRIAGE RETURN (CR)
 --  133 0085 NEXT LINE (NEL)

这六个都是\pC 类型,尤其是\p{Cc}。但是有 59 个非空白字符也是 \p{Cc}

% unichars '\P{WhiteSpace}' '\p{Cc}' | wc -l
      59

我自己测试某个东西是否是可打印字符的简单版本就是[\pZ\pC];例如,unichars 就是这样使用的。

更仔细的测试会考虑是否应该占用 0、1 或 2 个打印位置。这需要考虑它是否是组合标记,即属性\pM,以及它是否具有半角或全角属性。例如:

% uniprops ff5e ffeb
U+FF5E ‹~› \N{ FULLWIDTH TILDE }:
    \pS \p{Sm}
    All Any Assigned InHalfwidthAndFullwidthForms Changes_When_NFKC_Casefolded
       CWKCF Common Zyyy Sm S Gr_Base Grapheme_Base Graph GrBase Math
       Math_Symbol Print Symbol
U+FFEB ‹→› \N{ HALFWIDTH RIGHTWARDS ARROW }:
    \pS \p{Sm}
    All Any Assigned InHalfwidthAndFullwidthForms Changes_When_NFKC_Casefolded
       CWKCF Common Zyyy Sm S Gr_Base Grapheme_Base Graph GrBase Math
       Math_Symbol Print Symbol

对于这些,您需要使用非二进制东亚宽度属性。这些是适用的:

% uniprops -l | grep -i width
Block:Halfwidth_And_Fullwidth_Forms
InHalfwidthAndFullwidthForms
East_Asian_Width:A
East_Asian_Width=Ambiguous
East_Asian_Width:Ambiguous
East_Asian_Width:F
East_Asian_Width=Fullwidth
East_Asian_Width:Fullwidth
East_Asian_Width:H
East_Asian_Width=Halfwidth
East_Asian_Width:Halfwidth
East_Asian_Width=Neutral
East_Asian_Width:Na
East_Asian_Width=Narrow
East_Asian_Width:Narrow
East_Asian_Width:Neutral
East_Asian_Width:W
East_Asian_Width=Wide
East_Asian_Width:Wide

它们有\p{Ea=F}\p{Ea=H} 之类的缩写。有很多这样的:

% uninames '(FULL|HALF)WIDTH' | wc -l
     454

当然,你不能为这些东西命名,而要为属性:

% unichars '[\p{Ea=F}\p{Ea=H}]' | wc -l
     227
% unichars '[\p{Ea=F}\p{Ea=H}\p{Ea=Na}]' | wc -l
     338
% unichars '[\p{Ea=F}\p{Ea=H}\p{Ea=Na}\pM]' | wc -l
    1488

为了向您展示这些东西真正有多少、许多属性,这里是三个不同字符的完整属性转储,针对 Unicode 5.2 运行:

% uniprops -ga NEL "COMBINING TILDE" ff5e 
U+0085 ‹U+0085› \N{ NEXT LINE (NEL) }:
    \s \v \R \pC \p{Cc}
    All Any Assigned InLatin1 C Other Cc Cntrl Common Zyyy Control Pat_WS Pattern_White_Space PatWS Space SpacePerl VertSpace
       White_Space WSpace
    Age:1.1 Bidi_Class:B Bidi_Class=Paragraph_Separator Bidi_Class:Paragraph_Separator Bc=B Block:Latin_1
       Block=Latin_1_Supplement Block:Latin_1_Supplement Blk=Latin1 General_Category=Other Canonical_Combining_Class:0
       Canonical_Combining_Class=Not_Reordered Canonical_Combining_Class:Not_Reordered Ccc=NR Canonical_Combining_Class:NR
       General_Category=Control Script=Common Decomposition_Type:None Dt=None East_Asian_Width=Neutral East_Asian_Width:Neutral
       General_Category:C General_Category:Cc General_Category:Cntrl General_Category:Control Gc=Cc General_Category:Other Gc=C
       Grapheme_Cluster_Break:CN Grapheme_Cluster_Break=Control Grapheme_Cluster_Break:Control GCB=CN Hangul_Syllable_Type:NA
       Hangul_Syllable_Type=Not_Applicable Hangul_Syllable_Type:Not_Applicable Hst=NA Joining_Group:No_Joining_Group
       Jg=NoJoiningGroup Joining_Type:Non_Joining Jt=U Joining_Type:U Joining_Type=Non_Joining Line_Break:Next_Line Lb=NL
       Line_Break:NL Line_Break=Next_Line Numeric_Type:None Nt=None Numeric_Value:NaN Nv=NaN Present_In:1.1 Age=1.1 In=1.1
       Present_In:2.0 In=2.0 Present_In:2.1 In=2.1 Present_In:3.0 In=3.0 Present_In:3.1 In=3.1 Present_In:3.2 In=3.2
       Present_In:4.0 In=4.0 Present_In:4.1 In=4.1 Present_In:5.0 In=5.0 Present_In:5.1 In=5.1 Present_In:5.2 In=5.2
       Script:Common Sc=Zyyy Script:Zyyy Sentence_Break:SE Sentence_Break=Sep Sentence_Break:Sep SB=SE Word_Break:Newline WB=NL
       Word_Break:NL Word_Break=Newline
U+0303 ‹̃› \N{ COMBINING TILDE }:
    \w \pM \p{Mn}
    All Any Assigned InCombiningDiacriticalMarks Case_Ignorable CI Dia Diacritic M Mn Gr_Ext Grapheme_Extend Graph GrExt
       ID_Continue IDC Inherited Zinh Mark Nonspacing_Mark Print Qaai Word XID_Continue XIDC
    Age:1.1 Bidi_Class:Nonspacing_Mark Bc=NSM Bidi_Class:NSM Bidi_Class=Nonspacing_Mark Block:Combining_Diacritical_Marks
       Canonical_Combining_Class:230 Canonical_Combining_Class=Above Canonical_Combining_Class:A
       Canonical_Combining_Class:Above Ccc=A Decomposition_Type:None Dt=None East_Asian_Width:A East_Asian_Width=Ambiguous
       East_Asian_Width:Ambiguous Ea=A General_Category:M General_Category=Mark General_Category:Mark Gc=M General_Category:Mn
       General_Category=Nonspacing_Mark General_Category:Nonspacing_Mark Gc=Mn Grapheme_Cluster_Break:EX
       Grapheme_Cluster_Break=Extend Grapheme_Cluster_Break:Extend GCB=EX Hangul_Syllable_Type:NA
       Hangul_Syllable_Type=Not_Applicable Hangul_Syllable_Type:Not_Applicable Hst=NA Script=Inherited
       Joining_Group:No_Joining_Group Jg=NoJoiningGroup Joining_Type:T Joining_Type=Transparent Joining_Type:Transparent Jt=T
       Line_Break:CM Line_Break=Combining_Mark Line_Break:Combining_Mark Lb=CM NFC_Quick_Check:M NFC_Quick_Check=Maybe
       NFC_Quick_Check:Maybe NFCQC=M NFKC_Quick_Check:M NFKC_Quick_Check=Maybe NFKC_Quick_Check:Maybe NFKCQC=M
       Numeric_Type:None Nt=None Numeric_Value:NaN Nv=NaN Present_In:1.1 Age=1.1 In=1.1 Present_In:2.0 In=2.0 Present_In:2.1
       In=2.1 Present_In:3.0 In=3.0 Present_In:3.1 In=3.1 Present_In:3.2 In=3.2 Present_In:4.0 In=4.0 Present_In:4.1 In=4.1
       Present_In:5.0 In=5.0 Present_In:5.1 In=5.1 Present_In:5.2 In=5.2 Script:Inherited Sc=Zinh Script:Qaai Script:Zinh
       Sentence_Break:EX Sentence_Break=Extend Sentence_Break:Extend SB=EX Word_Break:Extend WB=Extend
U+FF5E ‹~› \N{ FULLWIDTH TILDE }:
    \pS \p{Sm}
    All Any Assigned InHalfwidthAndFullwidthForms Changes_When_NFKC_Casefolded CWKCF Common Zyyy Sm S Gr_Base Grapheme_Base
       Graph GrBase Math Math_Symbol Print Symbol
    Age:1.1 Bidi_Class:ON Bidi_Class=Other_Neutral Bidi_Class:Other_Neutral Bc=ON Block:Halfwidth_And_Fullwidth_Forms
       Canonical_Combining_Class:0 Canonical_Combining_Class=Not_Reordered Canonical_Combining_Class:Not_Reordered Ccc=NR
       Canonical_Combining_Class:NR Script=Common Decomposition_Type:Non_Canon Decomposition_Type=Non_Canonical
       Decomposition_Type:Non_Canonical Dt=NonCanon Decomposition_Type:Wide Dt=Wide East_Asian_Width:F
       East_Asian_Width=Fullwidth East_Asian_Width:Fullwidth Ea=F General_Category:Math_Symbol Gc=Sm General_Category:S
       General_Category=Symbol General_Category:Sm General_Category=Math_Symbol General_Category:Symbol Gc=S
       Grapheme_Cluster_Break:Other GCB=XX Grapheme_Cluster_Break:XX Grapheme_Cluster_Break=Other Hangul_Syllable_Type:NA
       Hangul_Syllable_Type=Not_Applicable Hangul_Syllable_Type:Not_Applicable Hst=NA Joining_Group:No_Joining_Group
       Jg=NoJoiningGroup Joining_Type:Non_Joining Jt=U Joining_Type:U Joining_Type=Non_Joining Line_Break:ID
       Line_Break=Ideographic Line_Break:Ideographic Lb=ID Numeric_Type:None Nt=None Numeric_Value:NaN Nv=NaN Present_In:1.1
       Age=1.1 In=1.1 Present_In:2.0 In=2.0 Present_In:2.1 In=2.1 Present_In:3.0 In=3.0 Present_In:3.1 In=3.1 Present_In:3.2
       In=3.2 Present_In:4.0 In=4.0 Present_In:4.1 In=4.1 Present_In:5.0 In=5.0 Present_In:5.1 In=5.1 Present_In:5.2 In=5.2
       Script:Common Sc=Zyyy Script:Zyyy Sentence_Break:Other SB=XX Sentence_Break:XX Sentence_Break=Other Word_Break:Other
       WB=XX Word_Break:XX Word_Break=Other

很漂亮,嗯?

如果您已经阅读了本文,并且想知道从哪里可以获得上述三个 Unicode 实用程序 unipropsunicharsuninames,请给我发邮件,因为当前链接不可用现在工作。

【讨论】:

  • other/format 块中还有一些东西——蒙古元音分隔符、零宽度(空格/连接器/非连接器)、单词连接器和零宽度不间断空格。它们是否可拆分应该会引发大量争论。
【解决方案4】:

也许来自多字节字符串函数集? http://php.net/manual/en/function.mb-ereg.php 看不到 mb_trim,但是有一组 MB 安全的正则表达式函数。

G

【讨论】:

    【解决方案5】:

    【讨论】:

    • 太棒了,谢谢!所以这也应该删除那些可怕的 Apple Logo 字符?优秀:-)
    【解决方案6】:

    但是这里是我唯一的解决方案,因为有时会有 UTF8 空格:

    $stringg = preg_replace('/^[\pZ\pC]+|[\pZ\pC]+$/u','',$stringg);
    $stringg = preg_replace('/\s+/u', '', $stringg);
    

    【讨论】:

    • 它有什么作用?修剪 unicode 空格,然后从字符串中删除所有空格?
    【解决方案7】:

    上面的答案都不能真正去除 utf-8 字符串中的尾随空格。

    找到here 的这个解决方案完美运行并且是最短的:

    trim($str, "\t\n\r\0\x0B\xC2\xA0");
    

    【讨论】:

    • 您的答案是 NOT Unicode/UTF-8 兼容:您将删除任何值为 0xC2 0xA0 或 ... ,而不是两个连续字节 0xC2 然后 0xA0 的序列(U+00A0 以 UTF-8 编码的方式)。这可能会导致 UTF-8 字符串损坏(除了您的答案中没有分配)!
    • 我明白你的意思。是的,这可能会破坏 UTF 字符串,因为它的字符是多字节的。但是在我的测试中,我在俄语-乌克兰语-英语文本上遇到了 0 个错误。可能是我很幸运,但这对我有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 2011-03-23
    • 1970-01-01
    • 2020-09-09
    • 2010-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多