【问题标题】:Adding conditional formatting and punctuation to a set of variables向一组变量添加条件格式和标点符号
【发布时间】:2010-10-19 14:24:57
【问题描述】:

我经常需要列出以逗号、空格或标点符号分隔的项目,地址是一个典型的例子(这对于一个地址来说太过分了,只是为了一个例子!):

echo "L$level, $unit/$num $street, $suburb, $state $postcode, $country.";
//ouput: L2, 1/123 Cool St, Funky Town, ABC 2000, Australia.

听起来很简单,有没有一种简单的方法可以“有条件地”仅在变量存在时在变量之间添加自定义分隔符?是否需要检查是否设置了每个变量?因此,使用上述方法,另一个细节较少的地址可能会输出如下内容:

//L, / Cool St, , ABC , .

一种稍微费力的检查方法是查看是否设置了每个变量并显示标点符号。

if($level){ echo "L$level, "; }
if($unit){ echo "$unit"; }
if($unit && $street){ echo "/"; }
if($street){ echo "$street, "; }
if($suburb){ echo "$suburb, "; }
//etc...

最好有一个可以自动执行所有剥离/格式化等的功能:

somefunction("$unit/$num $street, $suburb, $state $postcode, $country.");

另一个例子是一个简单的 csv 列表。我想输出以逗号分隔的 x 项:

for($i=0; $i=<5; $i++;){ echo "$i,"; }
//output: 1,2,3,4,5,

例如,在循环中,确定数组的最后一项或满足循环条件以在列表末尾不包含逗号的最佳方法是什么?我读过的一个很长的方法是在一个项目之前放一个逗号,除了第一个条目,比如:

$firstItem = true; //first item shouldn't have comma
for($i=0; $i=<5; $i++;){
  if(!$firstItem){ echo ","; }
  echo "$i";
  $firstItem = false;
}

【问题讨论】:

    标签: php variables formatting conditional


    【解决方案1】:

    对于您的第一个示例,您可以将数组与一些数组方法结合使用来获得所需的结果。例如:

    echo join(', ', array_filter(array("L$level", join(' ', array_filter(array(join('/', array_filter(array($unit, $num))), $street))), $suburb, join(' ', array_filter(array($state, $postcode))), $country))) . '.';
    

    这个单行代码读起来很复杂,所以总是可以将数组、array_filter 和 join 调用包装到一个单独的方法中,然后使用它:

    function merge($delimiter)
    {
        $args = func_get_args();
        array_shift($args);
        return join($delimiter, array_filter($args));
    }
    
    echo merge(', ', "L$level", merge(' ', merge('/', $unit, $num), $street), $suburb, merge(' ', $state, $postcode), $country) . '.';
    

    您需要调用 array_filter 来删除空条目,否则仍会打印出分隔符。

    对于第二个示例,将项目添加到数组中,然后使用 join 插入分隔符:

    $arr = array();
    for($i=0; $i=<5; $i++)
    {
        $arr[] = $i;
    }
    echo(join(',', $arr));
    

    【讨论】:

    • 如果我不得不维护您的代码,我宁愿在问题中看到类似“艰巨”的方法。这种单线解决方案是丑陋的。
    • 我同意单行可能难以阅读,因此我添加了另一个示例,将数组、array_filter 和 join 调用重构为辅助方法。
    【解决方案2】:

    虽然 Phillip 的回答解决了您的问题,但我想用Eric Lippert 的以下博客文章来补充它。尽管他的讨论是用 c# 进行的,但它适用于任何编程语言。

    【讨论】:

      【解决方案3】:

      你的第二个问题有一个简单的解决方案:

      for($i=0; $i<=5; $i++)
          $o .= "$i,";
      echo chop($o, ',');
      

      【讨论】:

        【解决方案4】:

        好的,拿去吧! (但不要太严重^^)

        <?php
        
        function bothOrSingle($left, $infix, $right) {
            return $left && $right ? $left . $infix . $right : ($left ? $left : ($right ? $right : null));
        }
        
        function leftOrNull($left, $postfix) {
            return $left ? $left . $postfix : null;
        }
        
        function rightOrNull($prefix, $right) {
            return $right ? $prefix . $right : null; 
        }
        
        function joinargs() {
            $args = func_get_args();
            foreach ($args as $key => $arg) 
                if (!trim($arg)) 
                    unset($args[$key]);
        
            $sep = array_shift($args);
            return join($sep, $args);
        }
        
        $level    = 2;
        $unit     = 1;
        $num      = 123;
        $street   = 'Cool St';
        $suburb   = 'Funky Town';
        $state    = 'ABC';
        $postcode = 2000;
        $country  = 'Australia';
        
        echo "\n" . '"' . joinargs(', ', rightOrNull('L', $level), bothOrSingle(bothOrSingle($unit, '/', $num), ' ', $street), bothOrSingle($state, ' ', $postcode), bothOrSingle($country, '', '.')) . '"';
        
        // -> "L2, 1/123 Cool St, ABC 2000, Australia."
        
        $level    = '';
        $unit     = '';
        $num      = '';
        $street   = 'Cool St';
        $suburb   = '';
        $state    = 'ABC';
        $postcode = '';
        $country  = '';
        
        echo "\n" . '"' . joinargs(
            ', ', 
            leftOrNull(
                joinargs(', ', 
                    rightOrNull('L', $level), 
                    bothOrSingle(bothOrSingle($unit, '/', $num), ' ', $street), 
                    bothOrSingle($state, ' ', $postcode), 
                    $country
                ),
                '.'
            )
        ) . '"';
        
        // -> "Cool St, ABC."
        
        
        $level    = '';
        $unit     = '';
        $num      = '';
        $street   = '';
        $suburb   = '';
        $state    = '';
        $postcode = '';
        $country  = '';
        
        echo "\n" . '"' . joinargs(
            ', ', 
            leftOrNull(
                joinargs(', ', 
                    rightOrNull('L', $level), 
                    bothOrSingle(bothOrSingle($unit, '/', $num), ' ', $street), 
                    bothOrSingle($state, ' ', $postcode), 
                    $country
                ),
                '.'
            )
        ) . '"';
        
        // -> "" (even without the dot!)
        
        ?>
        

        是的,我知道 - 看起来有点像笨蛋。

        【讨论】:

        • 天啊,我试图简化“艰苦”的做法:)它看起来像狗早餐,但元素是可用的。一旦确定了输出,joinargs 可以为每个输出提供函数,因此对于地址,只需调用:doaddress($level,$unit,$num,$street,$state,$postcode,$country);
        【解决方案5】:

        Philip 的解决方案在处理数组时可能是最好的(如果您不必过滤掉空值),但如果您不能使用数组函数——例如,在处理从 @987654321 返回的查询结果时@--那么一个解决方案就是一个简单的 if 语句:

        $list = '';
        $row=mysqli_fetch_object($result);
        do {
            $list .= (empty($list) ? $row->col : ", {$row->col}");
        } while ($row=mysqli_fetch_object($result));
        

        或者,或者:

        do {
            if (isset($list)) {
                $list .= ", {$row->col}";
            } else $list = $row->col;
        } while ($row=mysqli_fetch_object($result));
        

        要建立一个列表并过滤掉空值,我会编写一个自定义函数:

        function makeList() {
            $args = array_filter(func_get_args()); // as per Jon Benedicto's answer
            foreach ($args as $item) {
                if (isset($list)) {
                    $list .= ", $item";
                } else {
                    $list = $item;
                }
            }
            if (isset($list)) {
                return $list;
            } else return '';
        }
        

        那么你可以这样称呼它:

        $unitnum = implode('/',array_filter(array($unit,$num)));
        if ($unitnum || $street) {
            $streetaddress = trim("$unitnum $street");
        } else $streetaddress = '';
        if ($level) {
            $level = "L$level";
        }
        echo makeList($level, $streetaddress, $suburb, $state $postcode, $country).'.';
        

        【讨论】:

        • 我认为这已经接近了,街道地址可能还需要使用 makeList 函数,因为它仍然会返回空间和/如果三个变量中的任何一个为空白......因此主要部分的问题...
        • 您还对数组提出了一个很好的观点,数据通常来自 MySQL,这意味着创建一个或多个数组需要额外的步骤。
        • 有时,对于街道地址和级别等项目,最直接的解决方案就是使用简单的 if 语句进行自定义格式。构建一个自定义函数来处理一次性格式化问题是不切实际的。
        【解决方案6】:

        我总是发现使用语言的数组方法既快速又容易。例如,在 PHP 中:

        <?php
        echo join(',', array('L'.$level, $unit.'/'.$num, 
                  $street, $suburb, $state, $postcode, $country));
        

        【讨论】:

        • 除非在添加每个元素之前检查 isset 或 empty,否则无法解决问题。
        • 像我一样(见下文,#3)。不幸的是,这让它变得不那么优雅了。
        【解决方案7】:

        只需去掉最后一个逗号,即用空替换它。

        $string1 = "L$level, $unit/$num $street, $suburb, $state $postcode, $country.";
        $string1 = eregi_replace(", \.$", "\.", $string1);
        echo $string1;
        

        这样就可以了。

        【讨论】:

        • 我不这么认为,因为如果 $suburb 为空,中间会有双逗号(不好)。
        【解决方案8】:
        <?php
            $level  = 'foo';
            $street = 'bar';
            $num    = 'num';
            $unit   = '';
        
            // #1: unreadable and unelegant, with arrays
            $values   = array();
            $values[] = $level ? 'L' . $level : null;
            // not very readable ...
            $values[] = $unit && $num ? $unit . '/' . $num : ($unit ? $unit : ($num ? $num : null));
            $values[] = $street ? $street : null;
        
            echo join(',',  $values);
        
        
            // #2: or, even more unreadable and unelegant, with string concenation
            echo trim( 
                ($level ? 'L' . $level . ', ' : '') . 
                ($unit && $num ? $unit . '/' . $num . ', ' : ($unit ? $unit . ', ' : ($num ? $num . ', ': '')) .
                ($street ? $street . ', ': '')), ' ,');
        
            // #3: hey, i didn't even know that worked (roughly the same as #1):
            echo join(', ', array(
                $level ? 'L' . $level : null,
                $unit && $num ? $unit . '/' . $num : ($unit ? $unit : ($num ? $num : null)),
                $street ? $street : null
            ));
        ?>
        

        【讨论】:

        • 虽然这些解决方案有效,但对于看似简单的输出来说,这似乎是一些冗长的代码......对于更复杂的安排,让您了解这些选项会更加麻烦......谢谢为了贡献!
        • imho #3 还不错。在我的示例中,它看起来比实际更糟糕,因为我涵盖了 unit/num 组合的每个选项。如果有空值(没有“foo,,bar”),它会正确显示。有些人不喜欢 ? 的(有时很差)可读性。构造,坚韧。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        相关资源
        最近更新 更多