【问题标题】:Hebrew string reverse printing [duplicate]希伯来语字符串反向打印[重复]
【发布时间】:2018-09-08 21:34:25
【问题描述】:

我想echo 这一行:

$mother_name = "סבטלנה ואסילבנה"; 
echo strrev($mother_name);

结果是:�נבליסאו� �נלטבס�

怎么了?我从哪里得到这个 符号。 当我尝试echo 字符串中的单个字符时 我也得到 例如$mother_name[0]

【问题讨论】:

  • 我认为 PHP 在处理希伯来字符的字符集时遇到了困难,不过我可能错了..
  • 您不应该反转字符串,您应该使用 RTL 标记将希伯来语嵌入到其他 LTR 文档中。 en.wikipedia.org/wiki/Right-to-left_mark
  • 遗憾的是,几乎所有的 str* 函数都不适合多字节编码。它们作用于单个字节,而不是字符。
  • 不确定它是否有用,但我刚刚用 Scala 测试了它(使用与 Java 相同的 JVM 字符串),它会在正向打印 סבטלנה ואסילבנה 和 הנבליסאו הנלטבס 如果字符串反转。 Afair php 的字符串是字节数组,不能很好地处理 unicode...
  • @bobblebubble 你也不能像这样简单地反转一个 UTF 字符串,如果它包含组合标记、变音符号或其他类似的代码点,它会破坏字符串的内容。

标签: php right-to-left hebrew


【解决方案1】:

标记的重复答案也是错误的,原因与@bubbblebobble 的评论错误的原因相同。您不能简单地颠倒各个代码点的顺序并期望从另一侧出现一个健全的字符串。

intl 库通过IntlBreakIterator::createCharacterInstance() 提供了一个健全的方法来解释代码点的连贯序列

function utf8_strrev($input) {
    $it = IntlBreakIterator::createCharacterInstance('he_IL.utf8');
    $it->setText($input);

    $ret = '';
    $prev = 0;
    foreach ($it as $pos) {
        $ret = substr($input, $prev, $pos - $prev) . $ret;
        $prev = $pos;
    }
    return $ret;
}

function naieve_utf8_strrev($input) {
    return implode("", array_reverse(preg_split('//u', $input)));
}

$tests = [
    "test",
    "סבטלנה ואסילבנה",
    "nai\xcc\x88ve fail"
];

foreach($tests as $test) {
    var_dump(
        $test,
        naieve_utf8_strrev($test),
        utf8_strrev($test)
    );
    echo PHP_EOL;
}

输出:

string(4) "test"
string(4) "tset"
string(4) "tset"

string(29) "סבטלנה ואסילבנה"
string(29) "הנבליסאו הנלטבס"
string(29) "הנבליסאו הנלטבס"

string(12) "naïve fail"
string(12) "liaf ev̈ian"
string(12) "liaf evïan"

而且我仍然认为,如果您想要的只是从左到右显示希伯来语文本,那么尝试像这样反转希伯来语字符串是错误的方法。您应该使用 UTF8 LRO/RLO 和 PDF 标记来切换方向。

编辑:终于找到了正确的代码点。

function utf8_force_ltr($input) {
    $LRO = "\xe2\x80\xad"; // left-right override
    $PDF = "\xe2\x80\xac"; // pop directional formatting
    return $LRO . $input . $PDF;
}

var_dump($test, utf8_force_ltr($test));

输出:

string(29) "סבטלנה ואסילבנה"
string(35) "‭סבטלנה ואסילבנה‬"

【讨论】:

  • 感谢您的展示。你认为这也行不通preg_match_all('/\X/u', $input, $out)...?实际上我认为,空的正则表达式将在每个 \X 之间匹配,它匹配任意数量的 Unicode 字符,形成一个扩展的 Unicode 序列。
  • @bobblebubble \X 似乎确实有效。并不是说您的原始解决方案不能正确匹配多字节 UTF8 序列 [确实如此],而是单个屏幕上的字形可能由多个序列组成,即使在反转或以其他方式修改字符串时也必须保留其顺序。这就是为什么在使用 naieve 方法反转时,变音符号会应用于错误的字符。
猜你喜欢
  • 2017-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多