编译失败:不支持POSIX排序元素


Compilation failed: POSIX collating elements are not supported

我刚刚安装了一个网站&遗留CMS到我们的服务器上,我得到一个POSIX编译错误。幸运的是,它只出现在后端,但客户端热衷于摆脱它。

Warning: preg_match_all() [function.preg-match-all]: Compilation failed: 
POSIX collating elements are not supported at offset 32 in
/home/kwecars/public_html/webEdition/we/include/we_classes/SEEM/we_SEEM.class.php
on line 621

据我所知,这是新版本的PHP导致的问题。下面是代码:

function getAllHrefs($code){
$trenner = "['040|'n|'t|'r]*";
$pattern = "/<(a".$trenner."[^>]+href".$trenner."[='"|=''|=''''|=]*".$trenner.")
([^'''">'040? ''']*)([^'"'' '040''''>]*)(".$trenner."[^>]*)>/sie";
preg_match_all($pattern, $code, $allLinks); // ---- line 621
return $allLinks;
}

我如何调整这个工作在新版本的php在这个服务器上?

事先感谢,我的巫术不够强大;)

您的错误消息 "不支持POSIX排序元素" 值得一些解释。毕竟,POSIX排序元素到底是什么,我该如何避免它?

简短的回答是,在方括号内的地方有一个等号,它的使用是为将来保留的,假设我们有机会实现它,这是不确定的。您可以通过以下方式在Perl命令行中解决这个问题,它提供的错误消息比PHP提供的要好得多:

% perl -le 'print "abc" =~ /[=foo=]/ || "Fail"'
POSIX syntax [= =] is reserved for future extensions in regex; marked by <-- HERE in m/[=foo=] <-- HERE / at -e line 1.

这是简短的答案;更详细的答案如下:


花哨的POSIX字符类

在一个方括号字符类中,POSIX允许三种不同的嵌套方括号形式,它们都使用括号内的额外符号成对表示:

  1. 命名POSIX字符类,基本上类似于Unicode属性,使用额外的冒号:[:PROPERTY:],如[:alpha:]
  2. 排序元素被视为彼此相等,在它们的侧面使用一个额外的等号:[=ELEMENTS=],如英语或法语中的[=eéèëê=],和瑞典语中的[=vw=]
  3. 测谎仪(有向图、三向图、四向图等)是多字符元素,意味着算作一个字符,它们的侧面有一个额外的点:[.DIGRAPH.],如传统西班牙字母表中的[.ch.][.ll.]。这些有时被称为收缩,因为两个或更多的码点计数,好像该序列是一个码点。

Perl只支持第一种,不支持第二种和第三种。

使用起来都很别扭,因为它们必须嵌套在一组额外的括号中,就像在[[:punct:]中表示'pP'p{punct}一样。只有当您选择多个中的一个时,才需要额外的Unicode属性大括号,如['pL'pN'pM'p{Pc}]

意图

另外两个是在传统8位语言环境下的前Unicode环境中支持特定于语言环境的语言元素的尝试。例如,要表达传统的西班牙字母,它将重音计数为元音,将u s的变化计数为相同的字母,但将n上的波浪计数为完全不同的字母,并且还有两个有向图,每个都计数为不同的字母,您必须在POSIX中写:

[[=aá=]bc[.ch.]d[=eé=]fgh[=ií=]jkl[.ll.]mnñ[=oó=]pqrst[=uúü=]vwxyz]

你可以并且有时可以把它们结合起来。例如,在德语电话簿中,三个i突变的元音可以通过插入以下e来不加变音符符地拼写:

[a[=ä[.ae.]=]bcdefghijklmno[=ö[.oe.]=]pqrs[=ß[.ss.]=]tu[=ü[.ue.]=]vwxyz]

这样,假设$ES$DE是这些语言各自的字母,你可以写像

这样的东西
[$ES]{4}

并匹配西班牙语中的guíaniñollavechoco;或者在德语中有

[$DE]{6}

并让它匹配像 tsch 或它的大写不加变音符的等价词 tschess

Unicode方式

这很尴尬,原因有很多,不仅仅是上面列出的两个字母明显的原因。它不允许组合字符的概念,因此您必须为非规范化文本显式地添加这些字符,如[=e'xE9[.e'x{301.]=]

Unicode在如何实现这样的语言元素方面采取了另一种方式。幸运的是,在第3级之前,uts# 18中的Unicode正则表达式不需要支持为特定语言或地区量身定制的语言特性。这是目前还没有人实现的。

请注意,让SSß具有相同的case折叠不被认为是区域设置裁剪。无论语言上下文如何,它都是该代码点的完整案例。当忽略case时,它们是一样的。奇怪但却是事实。假设ß是代码点U+00DF,我们可以看到,无论语言环境如何,它们都是相同的:

$ perl5.14.0 -E 'say "SS" =~ /^'xDF$/i ? "Pass" : "Fail"'
Pass
$ perl5.14.0 -E 'say "'xDF" =~ /^SS$/i ? "Pass" : "Fail"'
Pass

尽管对模式的区域设置裁剪仍然超出了我们的能力范围,但排序已经实现,包括区域设置支持,并且您可以从Perl中访问它。

但是,PHP还不支持Unicode排序。


Unicode排序的参考包括:

  1. ICU的排序概念文档
  2. UTS#10: Unicode排序算法
  3. Perl的Unicode::Collate模块
  4. Perl的Unicode::Collate::Locale模块。

[...]字符类,它们匹配括号之间的任何字符,您不必在它们之间添加|。参见字符类。

因此[abcd]将匹配a or b or c or d

如果要匹配多个字符的替换,例如red or blue or yellow,请使用子模式:

"(red|blue|yellow)"

你猜,[abcd]等于(a|b|c|d)


那么你可以为你的regex做些什么:

$trenner = "['040|'n|'t|'r]*";

改为:

$trenner = "['040'n't'r]*";

"[='"|=''|=''''|=]"

你可以做

"(='"|=''|=''''|=)"

"=['"''''']?"

顺便说一句,你可以用's代替$trenner(见http://www.php.net/manual/en/regexp.reference.escape.php)