【问题标题】:How to increment letters like numbers in PHP?如何在PHP中增加数字等字母?
【发布时间】:2010-08-25 14:55:14
【问题描述】:

我想写一个函数,接收 3 个字符并将其递增,并将新递增的字符作为字符串返回。

我知道如何将单个字母增加到下一个字母,但我怎么知道何时增加第二个字母然后停止然后再次增加第一个字母以连续增加?

所以如果通过了 AAA,则返回 AAB。如果 AAZ 通过返回 ABA(困难部分)。

我将不胜感激有关逻辑以及哪些 php 函数有用的帮助。

更好的是,有些人已经这样做了,或者有一个类可以做到这一点??

感谢大家的帮助

【问题讨论】:

  • 我不明白。 AAA=>AAB 但 AAZ=>ABA。你如何决定增加哪些字母?你说增加第二个字母,所以我认为你的意思是除了第一个之外的所有字母?如果除第一个字母以外的所有字母都加一个,那不应该是 AAA=>ABB 吗?
  • @Raoul Duke:以 26 为底,没有数字,只有字母。
  • @Matt 好吧,这是有道理的。谢谢
  • @Raoul - 只需运行 $X = 'AAA'; for($i = 1; $i '; } 看看是什么意思。

标签: php


【解决方案1】:

字符/字符串增量在 PHP 中有效(尽管减量不起作用)

$x = 'AAZ';
$x++;
echo $x;  // 'ABA'

【讨论】:

  • 只可惜​​$x--不起作用。 @wimvds - 感谢您添加链接
  • 或者干脆echo ++$x; :)
  • 正如文档所说,decementing 应该使用 $a-- :php.net/manual/en/language.operators.increment.php
  • @TobiasGaertner - 递减 数字 适用于$a--;递减 characters/letters 不会... example... 并且您链接的文档页面专门说 Note that character variables can be incremented but not decremented
  • @Mark Ba​​ker - 是的,你是对的 - 我的错误 - 只是写得不够仔细。对不起
【解决方案2】:

您可以使用 ++ 运算符来做到这一点。

$i = 'aaz';
$i++;
print $i;

阿巴

然而这个实现有一些奇怪的地方:

for($i = 'a'; $i < 'z'; $i++) print "$i ";

这将打印出从ay 的字母。

for($i = 'a'; $i <= 'z'; $i++) print "$i ";

这将打印出从az 的字母,并以aa 继续并以yz 结束。

【讨论】:

  • 这并不奇怪,只是不直观。如果$i == 'z' 条件仍然成立,for 循环将继续,将$i 设置为'aa'。只有当$i 达到'za' 时,条件才会变为假。
【解决方案3】:

正如PHP RFC: Strict operators directive 中提出的(目前正在讨论中):

在启用 strict_operators 时对字符串使用增量函数将引发 TypeError。

无论 RFC 是否被合并,PHP 迟早会朝着增加运算符严格性的方向发展。因此,您不应该增加字符串

a-z/A-Z 范围

如果您知道您的字母将保持在 a-z/A-Z 范围内(不超过 z/Z),您可以使用将字母转换为 ASCII 码、将其递增并转换回字母的解决方案。

使用ord()chr()

$letter = 'A';
$letterAscii = ord($letter);
$letterAscii++;
$letter = chr($letterAscii); // 'B'
  1. ord() 将字母转换为 ASCII 数字表示
  2. num 表示增加了
  3. 使用chr() 将数字转换回字母

正如在 cmets 中发现的那样,要小心。这会迭代 ASCII 表,因此从 Z(ASCII 90)开始,它不会转到 AA,而是转到 [(ASCII 91)。

超越 z/Z

如果你敢更进一步,想要z变成aa,这就是我想出的:

final class NextLetter
{
    private const ASCII_UPPER_CASE_BOUNDARIES = [65, 91];
    private const ASCII_LOWER_CASE_BOUNDARIES = [97, 123];

    public static function get(string $previous) : string
    {
        $letters = str_split($previous);
        $output = '';
        $increase = true;

        while (! empty($letters)) {
            $letter = array_pop($letters);

            if ($increase) {
                $letterAscii = ord($letter);
                $letterAscii++;
                if ($letterAscii === self::ASCII_UPPER_CASE_BOUNDARIES[1]) {
                    $letterAscii = self::ASCII_UPPER_CASE_BOUNDARIES[0];
                    $increase = true;
                } elseif ($letterAscii === self::ASCII_LOWER_CASE_BOUNDARIES[1]) {
                    $letterAscii = self::ASCII_LOWER_CASE_BOUNDARIES[0];
                    $increase = true;
                } else {
                    $increase = false;
                }

                $letter = chr($letterAscii);
                if ($increase && empty($letters)) {
                    $letter .= $letter;
                }
            }

            $output = $letter . $output;
        }

        return $output;
    }
}

如果您打算进一步使用它,我也会为您提供 100% 的覆盖率。它针对原始字符串增量进行测试 ++:

    /**
     * @dataProvider letterProvider
     */
    public function testIncrementLetter(string $givenLetter) : void
    {
        $expectedValue = $givenLetter;

        self::assertSame(++$expectedValue, NextLetter::get($givenLetter));
    }

    /** 
     * @return iterable<array<string>>
     */
    public function letterProvider() : iterable
    {
        yield ['A'];
        yield ['a'];
        yield ['z'];
        yield ['Z'];
        yield ['aaz'];
        yield ['aaZ'];
        yield ['abz'];
        yield ['abZ'];
    }

【讨论】:

  • 我试过了,但不是从 zaa 而是到 { 和什么不是奇怪的字符..
  • 嗯,好点,我还没有走这么远。我已经编辑了答案。提供反馈对其他人也有帮助,谢谢 ;) 我会尝试在不增加字符串的情况下编写有效的解决方案并在此处发布。
【解决方案4】:

在7bits 128 chars ASCII范围内递增或递减,最安全的:

$CHAR = "l";
echo chr(ord($CHAR)+1)." ".chr(ord($CHAR)-1);
/* m k */

因此,通过递减a 得到反引号是正常的,因为ascii spec list

打印整个 ascii 范围:

for ($i = 0;$i < 127;$i++){
    echo chr($i);
}
/* !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ */

更多关于ANSI7 bits ASCII的信息:man ascii


8 位扩展的 256 字符 UTF-8 范围内递增或递减

这就是主机字符集开始不同的地方。但是这些字符集都可以在现代机器上使用。从php,最安全的是使用php-mbstring扩展:https://www.php.net/manual/en/function.mb-chr.php

扩展 ASCII(EASCII 或高位 ASCII)字符编码是 八位或更大的编码,包括标准七位 ASCII 字符,以及其他字符。 https://en.wikipedia.org/wiki/Extended_ASCII

更多信息,例如:man iso_8859-9

   ISO 8859-1    West European languages (Latin-1)
   ISO 8859-2    Central and East European languages (Latin-2)
   ISO 8859-3    Southeast European and miscellaneous languages (Latin-3)
   ISO 8859-4    Scandinavian/Baltic languages (Latin-4)
   ISO 8859-5    Latin/Cyrillic
   ISO 8859-6    Latin/Arabic
   ISO 8859-7    Latin/Greek
   ISO 8859-8    Latin/Hebrew
   ISO 8859-9    Latin-1 modification for Turkish (Latin-5)
   ISO 8859-10   Lappish/Nordic/Eskimo languages (Latin-6)
   ISO 8859-11   Latin/Thai
   ISO 8859-13   Baltic Rim languages (Latin-7)
   ISO 8859-14   Celtic (Latin-8)
   ISO 8859-15   West European languages (Latin-9)
   ISO 8859-16   Romanian (Latin-10)

例如,我们可以在 ISO 8859-7 中找到 符号:

244   164   A4     €     EURO SIGN

在 16 位 UTF-16 Unicode 范围内增加或减少

这是一种通过生成 html 实体并转换为 utf8 来生成整个 unicode 字符集的方法。 Run it online

for ($x = 0; $x < 262144; $x++){
  echo html_entity_decode("&#".$x.";",ENT_NOQUOTES,"UTF-8");
}

同样的东西,但范围上升到(16^4 * 4)

echo html_entity_decode('&#33;',ENT_NOQUOTES,'UTF-8');
/* ! */
echo html_entity_decode('&#34;',ENT_NOQUOTES,'UTF-8');
/* " */

要检索the unicode symbol,请使用字符的base10 十进制表示。

echo html_entity_decode('&#8364;',ENT_NOQUOTES,'UTF-8');
/* € */

同一个符号,使用base16十六进制表示:

echo html_entity_decode('&#'.hexdec("20AC").';',ENT_NOQUOTES,'UTF-8');
/* € */

前32位为special control characters保留,输出垃圾������,但有意义。

【讨论】:

    【解决方案5】:

    您正在研究数字表示问题。这是base24(或者你的字母表有多少数字)。让我们调用基础 b。

    为字母表中的每个字母分配一个数字(A=1、B=2、C=3)。

    接下来,计算你输入的“数字”:表示“ABC”表示A*b^2 + B*b^1 + C*b^0 使用此公式查找数字 (int)。增加它。

    接下来,将其转换回您的数字系统:除以 b^2 得到第三位,余数(模)除以 b^1 得到第二位,余数(模)除以 `b^0^ 得到最后一位.

    这可能会有所帮助:How to convert from base10 to any other base

    【讨论】:

    • 正确。我永远记不得字母表有多少个字母。这也取决于你如何计算(有些人省略了“j”和“v”,这对我来说似乎不是一个真正的字母......
    【解决方案6】:

    您可以将 ASCII 代码用于字母数字。从那里你递增和递减以获得上一个/下一个字符。

    您可以将字符串拆分为单个字符,然后对这些字符应用转换。

    只是一些让你开始的想法。

    【讨论】:

      【解决方案7】:
       <?php 
      $values[] = 'B';
      $values[] = 'A';
      $values[] = 'Z';
      foreach($values as $value ){
        if($value == 'Z'){ 
             $value = '-1';
          }
      $op = ++$value;
      echo $op;
      }
      ?>
      

      【讨论】:

      • 至少一点解释肯定会帮助 OP 和您的答案的进一步读者
      【解决方案8】:

      我在 c# 中有这些方法,您可能可以转换为 php 并根据您的需要进行修改,但我不确定 Hexavigesimal 是这些方法的确切名称...

      #region Hexavigesimal (Excel Column Name to Number)
      public static int FromHexavigesimal(this string s)
      {
          int i = 0;
          s = s.Reverse();
          for (int p = s.Length - 1; p >= 0; p--)
          {
              char c = s[p];
              i += c.toInt() * (int)Math.Pow(26, p);
          }
      
          return i;
      }
      
      public static string ToHexavigesimal(this int i)
      {
          StringBuilder s = new StringBuilder();
      
          while (i > 26)
          {
              int r = i % 26;
              if (r == 0)
              {
                  i -= 26;
                  s.Insert(0, 'Z');
              }
              else
              {
                  s.Insert(0, r.toChar());
              }
      
              i = i / 26;
          }
      
          return s.Insert(0, i.toChar()).ToString();
      }
      
      public static string Increment(this string s, int offset)
      {
          return (s.FromHexavigesimal() + offset).ToHexavigesimal();
      }
      
      private static char toChar(this int i)
      {
          return (char)(i + 64);
      }
      
      private static int toInt(this char c)
      {
          return (int)c - 64;
      }
      #endregion
      

      编辑

      我从其他答案中看到,在 PHP 中您可以改用 ++,很好!

      【讨论】:

      猜你喜欢
      • 2013-10-09
      • 2020-05-19
      • 1970-01-01
      • 2019-02-27
      • 1970-01-01
      • 2014-01-22
      • 2012-01-19
      • 1970-01-01
      • 2016-09-05
      相关资源
      最近更新 更多