14

どこかでこの問題が発生しました。PHP を使用してこれを解決する方法を知りたいです。このテキストを考えると:

$str = '
PHP is a
widely-used

general-purpose
server side

scripting
language
';

以下のようにテキストを垂直にエコーする方法:

      g        
      e        
      n        
      e        
  w   r s      
  i   a e      
  d   l r   s  
P e   - v   c l
H l   p e   r a
P y   u r   i n
  -   r     p g
i u   p s   t u
s s   o i   i a
  e   s d   n g
a d   e e   g e

答えとして、よりシンプルでエレガントなコードを選択します。

4

15 に答える 15

9

他の人がすでに示したarray_mapように、基本的にあなたが解決する必要がある主な問題であるフリップオーバーを行うことができます。残りは、コードを配置する方法です。わかりやすいのでとても良いバージョンだと思います。

他の極端なものを探している場合は、注意して取り扱ってください。

$str = 'PHP is a
widely-used

general-purpose
server side

scripting
language';
    
$eol = "\n";
$turned = function($str) use ($eol) {
    $length = max(
        array_map(
            'strlen',
            $lines = explode($eol, trim($str))
        )
    );
    $each = function($a, $s) use ($length) {
        $a[] = str_split(
            sprintf("%' {$length}s", $s)
        );
        return $a;
    };
    return implode(
        $eol,
        array_map(
            function($v) {
                return implode(' ', $v);
            },
            call_user_func_array(
                'array_map',
                array_reduce($lines, $each, array(NULL))
            )
        )
    );
};
echo $turned($str), $eol;

あなたにあげる:

      g        
      e        
      n        
      e        
  w   r s      
  i   a e      
  d   l r   s  
P e   - v   c l
H l   p e   r a
P y   u r   i n
  -   r     p g
i u   p s   t u
s s   o i   i a
  e   s d   n g
a d   e e   g e

これにより、正しくなかった他の回答の出力が修正されます(現在は修正されています)。

于 2012-06-02T22:21:12.863 に答える
6

以下のコードは$str縦に印刷されます。

$lines = preg_split("/\r\n/", trim($str));
$nl    = count($lines);
$len   = max(array_map('strlen', $lines));

foreach ($lines as $k => $line) {
  $lines[$k] = str_pad($line, $len, ' ', STR_PAD_LEFT);
}

for ($i = 0; $i < $len; $i++) {
  for ($j = 0; $j < $nl; $j++) {
    echo $lines[$j][$i].($j == $nl-1 ? "\n" : " ");
  }
}
于 2012-05-28T12:41:19.740 に答える
3
$a = explode(PHP_EOL, trim($str));
$h = max(array_map('strlen', $a));
$w = count($a);
$m = array_map('str_split', array_map('sprintf', array_fill(0, $w, "%{$h}s"), $a));
$t = call_user_func_array('array_map', array_merge(array(null), $m));
echo implode(PHP_EOL, array_map('implode', array_fill(0, $h, ' '), $t)), PHP_EOL;

PHP_EOLは、必要に応じて「\ n」、「\ r \ n」、または「<br/>」に置き換える必要があります。最初の行の後のコード全体が簡単に1つの大きな式になる可能性があり、その可読性だけが少し損なわれます;-)

$aは行の配列、$hは最終的な高さ、$wは最終的な幅、$mは文字の行列(文字列をパディングした後)、$tは転置された行列です。

列間のarray_fill(0, $h, ' '),スペースが必要ない場合は、最後の行のを単純に省略できます。一方、末尾のスペース文字を印刷しないことは、次のように実現できます。

echo implode(PHP_EOL, array_map('rtrim', array_map('implode', array_fill(0, $h, ' '), $t))), PHP_EOL;

私はこの質問を、明示的なループ(この場合は利点が失われる可能性がありますが、通常はPHP関数内のループよりも高価です)を回避するための演習として取り上げました。ここで重要なトリックは、Codlerによるこの回答から取ったマトリックス転置です。

とにかく、アルゴリズム全体の複雑さは、O(width × height)このページのほとんどのアルゴリズムの1つと同じですが、行を取得するために文字列を繰り返し連結するアルゴリズムを除きます。O(width² × height)

于 2012-05-31T22:28:22.337 に答える
1

私はこれを試してみます:

$arrlines = explode(PHP_EOL, trim($str));
$max = max(array_map('strlen', $arrlines));
foreach($arrlines as $val)
    $arrlines = str_pad($val,$max," ",STR_PAD_LEFT);    
for($x=0;$x<$max;$x++){
    for($y=0;$y<count($arrlines);$y++)
        $string .= strlen(trim($arrlines[$y][$x])) > 0 ? $arrlines[$y][$x]."&nbsp;":"&nbsp;&nbsp;";
    $string .= "\n";
    }
echo '<pre>'.$string.'</pre>';

行番号:

  1. PHP 定数 PHP_EOL で区切られた配列 $arrlines に行ごとに文字列を保存します
  2. 文字列の最大長を取得し、$max に保存します
  3. $arrlines のすべての要素に対してループし、次に
  4. 文字列の左側にパディングを追加して、文字列の長さを $max に等しくします

5 ~ 9 行目では、ネストされたループで $arrline[$y][$x] を $string に保存し、10 行目で結果を出力します。

結果はこちらでご覧いただけます

于 2012-06-04T18:59:57.647 に答える
0

文字列の長さと配列内の要素の数は、変数ごとに PHP によってキャッシュされることに注意してください。strlen または count を繰り返し呼び出すと、空の関数呼び出しによるパフォーマンスの低下のみが生じます (その後の呼び出しでは、長さまたはカウントが PHP によって内部的に 2 回測定されることはありません)。

これは、Mac (\r)、Linux (\n) または Windows (\r\n) の入力文字列、および/または空の入力文字列、および/または 1 行の入力文字列で動作し、優先される出力で動作します行区切り文字 (デフォルトは PHP_EOL):

function matrix_vertical_align_bottom($str, $strEOL=PHP_EOL)
{
    $arrLines=explode("\n", $str);

    $nMaxLength=max(array_map("strlen", $arrLines));
    $nRotatedWidth=count($arrLines)+strlen($strEOL);

    //allocate once
    $strRotated=str_pad(
        "", 
        $nRotatedWidth*$nMaxLength-strlen($strEOL), 
        str_repeat(" ", count($arrLines)).$strEOL
    );

    foreach($arrLines as $nRotatedColumnIndex=>$strLine)
    {
        $nRotatedVerticalPadding=$nMaxLength-strlen($strLine);
        for($nColumnIndex=strlen($strLine)-1; $nColumnIndex>=0; $nColumnIndex--)
            $strRotated[$nRotatedWidth*($nColumnIndex+$nRotatedVerticalPadding)+$nRotatedColumnIndex]=$strLine[$nColumnIndex];
    }

    return $strRotated;
}

echo matrix_vertical_align_bottom(preg_replace("/(\r\n|\r|\n)/", "\n", trim($str)));

パフォーマンスはかなり良好です。上記のアルゴリズムは、文字列を 90 度回転させながら座標を変換しているだけです。個々の行をパディングすることによって引き起こされる文字列の拡張のため、メモリの再割り当てはありません (多数の行を含む入力文字列の場合、これはパフォーマンス ヒットになります)。

HTML 出力は想定されていません。nl2br(htmlspecialchars( )) を出力する場合は、トリック + 等幅フォントを使用する必要があります。

于 2012-06-01T18:08:31.183 に答える
0

この答えを確認してください:

<?php

$str = 'PHP is a
widely-used

general-purpose
server side

scripting
language';


function getVerticalString($str){
    $str = preg_split('/\r|\n/',$str);

    $maxlength = 0;

    $totalstr = count($str);

    for($i=0;$i<$totalstr;$i++){
        if($maxlength<strlen($str[$i])){
            $maxlength = strlen($str[$i]);
        }
    }

    $strings = array();

    for($i=0;$i<$maxlength;$i++){
        $strings[$i] = "";
        for($j=0;$j<$totalstr;$j++){
            $temp = strlen($str[$j])-($maxlength-$i);
            if($temp>=0){
                $strings[$i] .= substr($str[$j],$temp,1);
            }
            else{
                $strings[$i] .= " ";
            }
        }
    }

    return implode("\r",$strings);
}

echo "<pre>".getVerticalString($str)."</pre>";

これは以下を出力します:

   g    
   e    
   n    
   e    
 w rs   
 i ae   
 d lr s 
Pe -v cl
Hl pe ra
Py ur in
 - r  pg
iu ps tu
ss oi ia
 e sd ng
ad ee ge

あなたの要件に従って。:)

于 2012-06-04T08:18:35.833 に答える
0

短いとは言えませんが、行数は少ないです ;-)

$nr_lines = count($lines = preg_split('/\r?\n/', trim($str)));
$maxlen = max($lengths = array_map('strlen', $lines)); // get line lengthts and maximum
$line_ptrs = array_fill(0, $nr_lines, 0); // last character position per line

for ($j = 0; $j != $maxlen; ++$j) {
    for ($i = 0; $i != $nr_lines; ++$i) {
        // $maxlen - $lengths[$i] indicates where printing start for this line
        echo $j >= $maxlen - $lengths[$i] ? $lines[$i][$line_ptrs[$i]++] : ' ';
    }
    echo "\n";
}

パディングと印刷を同じ内部ループで行い、$line_ptrsand$lengths配列を使用して次に印刷する文字を追跡します。

基準

10,000 回の反復に基づくと、このコードは最初の回答よりも 19% 優れたパフォーマンスを発揮します。

于 2012-06-04T09:06:05.963 に答える
0

古いことわざのようです:

正規表現なしで実行できる場合は、とにかく試してください。

問題に直面したときに、「分かった、正規表現を使用する」と考える人もいます。今では問題はありません。

「私はあまり人が通らない [道] を選びました」 - ロバート・フロスト

このページには似たようなテクニックがたくさんあるので、新しい視点を提供したいと思いました。入力文字列がループ内で消費され、各行の最後の文字 (存在する場合) がスペース区切りの文字列として出力配列に追加される手法を次に示します。入力文字列全体が空白文字で構成されている場合、ループは中断されます。私はそれをベンチマークしませんでしたが、誰かが調査結果を提供する傾向がある場合は、比較を聞いてみたいと思います.

コード: (デモ)

$result = [];
while (!ctype_space($string)) {
    $line = [];
    $string = preg_replace_callback(
        "~.$|^$~m",
        function($m) use(&$line) {
            $line[] = $m[0] === '' ? ' ' : $m[0];
            return '';
        },
        $string,
    );
    array_unshift($result, implode(' ', $line));
}
echo implode("\n", $result);
于 2021-09-14T03:18:16.770 に答える
0

これは、誰でもこのコードを理解できる簡単なコードです

    $str = '
    PHP is a
    widely-used

    general-purpose
    server side

    scripting
    language
    ';

    $lines = array();

    $sentences = explode("\n\n",$str);
    foreach($sentences as $sentence){
        if($sentence != ""){
            $each_lines = explode("\n",$sentence);
            foreach($each_lines as $each_line){
                if($each_line != ""){
                    $lines[] = $each_line;
                }
            }
            $lines[] = "\t";
        }
    }
    $before_sort = $lines;
    usort($lines, "cmp_len");
    $big_length = strlen($lines[0]);
    foreach($before_sort as $key=>$arr){
        $this_length = strlen($arr);
        if($this_length < $big_length){
            $no_of_letters = $big_length - $this_length;
            $text = "";
            for($i=0;$i<$no_of_letters;$i++){
                $text .= " ";
            }
            $text .= $before_sort[$key];
            $before_sort[$key] = $text;
        }
    }

    $temp = array();
    echo "<table>";
    for($i=0;$i<$big_length;$i++){
      echo "<tr>";
        foreach($before_sort as $arr){
            echo "<td>";
                echo str_replace("\t","&nbsp;&nbsp;&nbsp;&nbsp;",$arr[$i]);
            echo "</td>";
        }
      echo "</tr>";
    }
    echo "</table>";





    function cmp_len($a, $b){
       return (strlen($a)  < strlen($b));
    }
于 2012-06-04T04:41:50.373 に答える
-1

これを試して、

$str = 'PHP is a
widely-used

general-purpose
server side

scripting
language';

$strArr = explode("\r\n", $str);
$max =max(array_map('strlen', $strArr));

for($i=0; $i< $max;$i++)
{
    for($x=0;$x < count($strArr); $x++)
    {
        $strVal = $strArr[$x];
        $y = $i -($max -  strlen($strVal));
        $vertical .= strlen(trim($strVal[$y]))<> 0 ? $strVal[$y]." " : "  ";
    } 
    $vertical .="\n";
}
echo "<pre>".$vertical;
于 2012-06-04T13:11:55.513 に答える
-1

これが私のショットです。ネストされたループなしでそれを行う方法を理解できませんでした。

$lines = array_map('strrev', explode("\r\n", trim($str)));
$new = array();
foreach(range(0, max(array_map('strlen', $lines))) as $i){ 
    foreach($lines as $line){
        $new[$i] .= (!empty($line[$i]) ? $line[$i] . ' ' : '  ');
    }
}
echo implode("\r\n", (array_slice(array_reverse($new), 1)));
于 2012-05-31T06:53:24.627 に答える
-1

最善かつ最も簡単な方法:)

<style type="text/css">
#heading{
    /* vertical text css */
    width:1em;
    text-transform:uppercase;
}
</style>

<h1 align="center" id="heading">h e l l o</h1>

デモ

于 2012-06-05T13:30:08.293 に答える