【问题标题】:PHP: split string based on arrayPHP:基于数组拆分字符串
【发布时间】:2016-12-31 01:32:40
【问题描述】:

以下是我要解析的数据:

50‐59 1High300.00 Avg300.00
90‐99 11High222.00 Avg188.73
120‐1293High204.00 Avg169.33

第一部分是权重范围,接下来是计数,接着是Highprice,以Avgprice结束>.

例如,我需要将上面的数据解析成一个数组,看起来像

[0]50-59
[1]1
[2]High300.00
[3]Avg300.00

[0]90-99
[1]11
[2]High222.00
[3]Avg188.73

[0]120‐129
[1]3
[2]High204.00
[3]Avg169.33

我想过创建一个可能的权重范围的数组,但我不知道如何使用数组的值来拆分字符串。

$arr = array("10-19","20-29","30-39","40-49","50-59","60-69","70-79","80-89","90-99","100-109","110-119","120-129","130-139","140-149","150-159","160-169","170-179","180-189","190-199","200-209","210-219","220-229","230-239","240-249","250-259","260-269","270-279","280-289","290-299","300-309");

任何想法将不胜感激。

【问题讨论】:

  • 该格式是否一致,或者count可以超过10?最好在每个值之间有一个分隔符。这个字符串是怎么生成的?
  • @chris85 我同意在值之间有一个分隔符是可取的,但我无法控制给我的数据:(要回答你的问题,是的,计数可以超过 10 . 我唯一可以安全假设的是计数将小于 999。
  • 字符串是在哪里/如何生成的?
  • @chris85 数据是从我无法控制的外部系统发送的。

标签: php regex


【解决方案1】:

让我们来解决这个看似废弃的问题:

这是您可以信任的模式 (Pattern Demo):

^((\d{0,2})0\‐(?:\2)9) ?(\d{1,3})High(\d{1,3}\.\d{2}) ?Avg(\d{1,3}\.\d{2})

其他答案忽略了weight range 子字符串中的数字模式。范围起始整数始终以0 结尾,范围结束整数始终以9 结尾;范围总是跨越十个整数。

我的模式将捕获起始整数中0 之前的数字,并在短划线后立即引用它们,然后要求捕获的数字后跟9

我想指出您的示例输入有点棘手,因为您的 不是标准的-,它位于我键盘上的0= 之间。这是我要解决的一个偷偷摸摸的小问题。

方法(Demo):

$keys=['weight range','count','Highprice','Avgprice'];
$in='50‐59 1High300.00 Avg300.00
90‐99 11High222.00Avg188.73
120‐1293High204.00 Avg169.33';

$out=preg_match_all('/((\d{0,2})0\‐(?:\2)9) ?(\d{1,3})High(\d{1,3}\.\d{2}) ?Avg(\d{1,3}\.\d{2})/',$in,$out)?array_diff_key($out,[0=>'',2=>'']):[];
// array_diff_key removes unwanted matching subarrays
foreach($out as $i=>$v){
    $result[]=array_combine($keys,array_column($out,0));
}
var_export($result);

输出:

array (
  0 => 
  array (
    'weight range' => '50‐59',
    'count' => '1',
    'Highprice' => '300.00',
    'Avgprice' => '300.00',
  ),
  1 => 
  array (
    'weight range' => '50‐59',
    'count' => '1',
    'Highprice' => '300.00',
    'Avgprice' => '300.00',
  ),
  2 => 
  array (
    'weight range' => '50‐59',
    'count' => '1',
    'Highprice' => '300.00',
    'Avgprice' => '300.00',
  ),
  3 => 
  array (
    'weight range' => '50‐59',
    'count' => '1',
    'Highprice' => '300.00',
    'Avgprice' => '300.00',
  ),
)

【讨论】:

    【解决方案2】:

    $arr = array('50-59 1High300.00 Avg300.00', 
                 '90-99 11High222.00 Avg188.73', 
                 '120-129 3High204.00 Avg169.33');
    
    foreach($arr as $str) {
        if (preg_match('/^(\d+-\d{1,3})\s*(\d+)(High\d+\.\d\d) (Avg\d+\.\d\d)/i', $str, $m)) {
            array_shift($m); //remove group 0 (ie. the whole match)
            $result[] = $m;
        }
    }
    print_r($result);
    

    输出:

    Array
    (
        [0] => Array
            (
                [0] => 50-59
                [1] => 1
                [2] => High300.00
                [3] => Avg300.00
            )
    
        [1] => Array
            (
                [0] => 90-99
                [1] => 11
                [2] => High222.00
                [3] => Avg188.73
            )
    
        [2] => Array
            (
                [0] => 120-129
                [1] => 3
                [2] => High204.00
                [3] => Avg169.33
            )
    
    )
    

    说明:

    /                   : regex delimiter
        ^               : begining of string
        (               : start group 1
          \d+-\d{1,3}   : 1 or more digits a dash and 1 upto 3 digits ie. weight range
        )               : end group 1
        \s*             : 0 or more space character
        (\d+)           : group 2 ie. count
        (High\d+\.\d\d) : group 3 literal High followed by price
        (Avg\d+\.\d\d)  : Group 4 literal Avg followed by price
    /i                  : regex delimiter and case Insensitive modifier.
    

    为了更通用,您可以将 HighAvg 替换为 [a-z]+

    【讨论】:

      【解决方案3】:
      '#^([\d]+\-[\d]+) ([\d]+)([a-zA-Z]+[\d\.]+) ([a-zA-Z]+[\d\.]+)#'
      

      我认为这行不通,因为您在正则表达式中有空间 在重量和计数之间。我正在挣扎的事情是一排 像这样没有空间的地方。 120‐1293High204.00 Avg169.33那个 需要像[0]120‐129 [1]3 [2]High204.00 [3]Avg169.33一样解析

      你是对的。这可以通过将重量位数限制为三个并使空格可选来解决。

      '#^(\d+-\d{1,3}) *…
      

      【讨论】:

        【解决方案4】:

        希望这会奏效:

            $string='50-59 1High300.00 Avg300.00
            90-99 11High222.00 Avg188.73
            120-129 3High204.00 Avg169.33';
        
            $requiredData=array();
            $dataArray=explode("\n",$string);
            $counter=0;
            foreach($dataArray as $data)
            {
                if(preg_match('#^([\d]+\-[\d]+) ([\d]+)([a-zA-Z]+[\d\.]+) ([a-zA-Z]+[\d\.]+)#', $data,$matches))    
                {
                    $requiredData[$counter][]=$matches[1];
                    $requiredData[$counter][]=$matches[2];
                    $requiredData[$counter][]=$matches[3];
                    $requiredData[$counter][]=$matches[4];
                    $counter++;
                }
            }
            print_r($requiredData);
        

        【讨论】:

        • 非常感谢您的建议,我承认我的正则表达式知识不是很好,但我认为这不会起作用,因为您在正则表达式中的权重和计数之间有空间.我正在努力解决的问题是像这样没有空间的一排。 120-1293High204.00 Avg169.33 需要像 [0]120-129 [1]3 [2]High204.00 [3]Avg169.33 进行解析
        猜你喜欢
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 2018-12-29
        • 2019-05-08
        • 2014-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多