【问题标题】:Character in php takes 3 placesphp中的字符占3个位置
【发布时间】:2019-11-25 17:36:32
【问题描述】:

我在字符串(字符数组)中有一个问题,因为一个字符占据了 3 个位置,这使我的代码产生了意想不到的结果

检查此代码:

<?php
$input1="t’n";
for($i=0;$i<strlen($input1);$i++){
    echo $input1[$i] .'<br/>';
}
echo '<br>'.'=================='.'<br>';
$input2='test';
for($i=0;$i<strlen($input2);$i++){
    echo $input2[$i] .'<br/>';
}
echo '<br>'.'Strange ===> ';
echo $input1[1].$input1[2].$input1[3];

看照片:

我们注意到这个字符在将字符串作为字符数组处理时占据 3 个位置,并且三个必须保持在一起才能生成正确的字符。

我在制作一个反转我输入的字符串的代码时遇到这种情况,包含这个字符 例如 t'n => n't 有什么建议吗?

提前致谢

【问题讨论】:

  • 您在字符串中检查的撇号似乎是您的文本编辑器识别和处理的不同编码,但您的代码正在使用它的标准编码。我可能没有说最好,但希望你明白我的意思。标准化和清理您的输入,这应该不是问题。
  • 谢谢。这是一个未通过此案例的问题解决测试。有没有办法用代码处理这个问题?
  • 尝试熟悉搜索php手册。相当有据可查。也许不是最好的方法,但我会尝试一个解决方案。 (也许有人有更好的解决方案)
  • 我检查了 php 手册,但没有找到或者我应该搜索什么词?!
  • 不知道你有没有在我的回答中看到,但是搜索“编码”,不要害怕阅读很多。如果你这次学到了你不需要的东西,下次你仍然会拥有它。或者按照 Pierre 的描述自己进行逆向工程。(会让你更好地理解)

标签: php arrays string reverse


【解决方案1】:

如您所见,只要字符串包含多字节字符,就不能像使用数组那样使用字符串。没关系,我们将使用 mb_* 函数来提取每个字符:

$input = 't’n';
$result = [];

for ($i=0, $max=mb_strlen($input); $i < $max; $i++) {
    $result[] = mb_substr($input, $i, 1); 
}

echo implode('<br>', $result);

好的,看起来不错,用array_reverse可以很容易得到一个反转字符串:

echo implode('', array_reverse($result));

但这并不是那么简单。让我们考虑一个包含组合字符的字符串:

$input = "a\xcc\x80e"; // àe

这个字符串有三个代码点:

  • U+0061 拉丁文小写字母 A (\x61)
  • U+0300 结合重音 (\xcc\x80)
  • U+0065 拉丁文小写字母 E (\x65)

问题:如果我们使用前面的代码来反转这个字符串,我们会以相反的顺序获得三个代码点,所以字符串"e\xcc\x80a" // èa。请注意,现在重音出现在 e 上,而不再出现在 a 上。

为了获得预期的结果 ("ea\xcc\x80"),我们必须不使用字节,不使用代码点,而是使用字形。 (字形包括字符和与其结合的最终字符)。

为此,我们可以使用grapheme_* functions 代替mb_* 功能完全相同:

for ($i=0, $max=grapheme_strlen($input); $i < $max; $i++) {
    $result[] = grapheme_substr($input, $i, 1); 
}

其他可能性,我们可以使用匹配字素的\X pcre 功能:

if ( preg_match_all('~\X~u', $input, $matches) ) {
    $result = $matches[0];
}

Nota Bene:您显然可以避免创建一个数组来反转字符串:

function grapheme_strrev($input) {
    $result = '';
    for ($i = grapheme_strlen($input) - 1; $i > -1; $i--) {
        $result .= grapheme_substr($input, $i, 1);
    }
    return $result;
}

【讨论】:

    【解决方案2】:

    那个字符是右单引号,U+2019(数字是十六进制的)。在 UTF-8 中,编码为 e2 80 99。所以当你反转 74 e2 80 99 6e 时,你需要使 6e e2 80 99 74。

    您可以按如下方式在字节字符串中处理它:

    • 从 $input 的末尾迭代 $i 到开头。
    • 如果 $input[$i] 介于 0 和 127 之间,请将其复制到 $output 的末尾。
    • 如果 $input[$i] 介于 128 和 191 之间(或者如果 char 是有符号的,则介于 -128 和 -65 之间),保持它。
    • 如果 $input[$i] 介于 192 和 255(-64 和 -1)之间,请将其和保存的字节作为一个块复制到 $output 的末尾。

    以 UTF-8 编码的所有 Unicode 字符要么是一个 7 位字符,即高位清零的字节,要么是一个多字节序列,其中第一个字节从 11 开始,其余所有字节从 10 开始。

    UTF-8 中存在无效的字节序列(例如,您永远不会看到字节 fe 和 ff);你如何处理它们取决于你。

    【讨论】:

      【解决方案3】:

      这不起作用,我现在没有时间做更多事情。但是您应该能够使用几个函数来检测字符编码,并在必要时进行转换。我不知何故怀疑这是你练习的目标......似乎是一个非常昂贵(计算)的检查。无论哪种方式,在手册中搜索编码功能,并执行类似于以下的操作 - 您将能够处理每个字符。无论出于何种原因,我都无法在 CLI 中成功调用转换函数。

      <?php
      $input1="t’n";
      $ce = mb_internal_encoding(); //current encoding in use by php/this script by X configuration
      for($i=0;$i<strlen($input1);$i++){
          if(mb_detect_encoding($input1[$i], "auto", true) == $ce){
              echo $input1[$i] .'<br/>';
          }
          else{
              echo mb_convert_encoding($input1[$i], $ce, "auto");
          }
      }
      echo '<br/>'.'=================='.'<br/>';
      $input2='test';
      for($i=0;$i<strlen($input2);$i++){
          echo $input2[$i] .'<br/>';
      }
      

      抱歉,不完整,希望对您有所帮助,或者比我更有知识的人可以加入...

      【讨论】:

      • 为什么是-1来提供正确的功能并指出正确的方向?我认为这不应该是一个复制和粘贴农场……或者至少用更好的方法发表评论。
      猜你喜欢
      • 2012-12-14
      • 2019-02-27
      • 1970-01-01
      • 1970-01-01
      • 2012-04-23
      • 1970-01-01
      • 2013-12-29
      • 1970-01-01
      • 2016-02-23
      相关资源
      最近更新 更多