PHP ve RegEx: parantezleri (ve aynı zamanda iç içe parantez) değil virgülle bir dize Böl

6 Cevap php

İki gün önce ben bir kod çözümleyici üzerinde çalışmaya başladı ve ben şaşırıp.

Ben parantezleri değil virgülle bir dize bölmek nasıl, bana ne demek istediğimi göstereyim:

Ben ayrıştırmak bu dizesi vardır:

one, two, three, (four, (five, six), (ten)), seven

Ben bu sonucu almak istiyorum:

array(
 "one"; 
 "two"; 
 "three"; 
 "(four, (five, six), (ten))"; 
 "seven"
)

ama onun yerine ben alıyorum:

array(
  "one"; 
  "two"; 
  "three"; 
  "(four"; 
  "(five"; 
  "six)"; 
  "(ten))";
  "seven"
)

Nasıl PHP RegEx'in yapabilirsiniz.

Şimdiden teşekkürler!

6 Cevap

Bunu daha kolay yapabilirsiniz:

preg_match_all('/[^(,\s]+|\([^)]+\)/', $str, $matches)

Gerçek bir ayrıştırıcı kullanmak Ama eğer daha iyi olurdu. Belki böyle bir şey:

$str = 'one, two, three, (four, (five, six), (ten)), seven';
$buffer = '';
$stack = array();
$depth = 0;
$len = strlen($str);
for ($i=0; $i<$len; $i++) {
    $char = $str[$i];
    switch ($char) {
    case '(':
        $depth++;
        break;
    case ',':
        if (!$depth) {
            if ($buffer !== '') {
                $stack[] = $buffer;
                $buffer = '';
            }
            continue 2;
        }
        break;
    case ' ':
        if (!$depth) {
            continue 2;
        }
        break;
    case ')':
        if ($depth) {
            $depth--;
        } else {
            $stack[] = $buffer.$char;
            $buffer = '';
            continue 2;
        }
        break;
    }
    $buffer .= $char;
}
if ($buffer !== '') {
    $stack[] = $buffer;
}
var_dump($stack);

Hm ... Tamam yanıtladı zaten işaretlenmiş, ancak kolay bir çözüm istedi beri ben yine çalışacağız:

<?php
  $test = "one, two, three, , , ,(four, five, six), seven, (eight, nine)";
  $split = "/([(].*?[)])|(\w)+/";
  preg_match_all($split, $test, $out);
  print_r($out[0]);              
  die();
?>

Çıktı

Array
(
    [0] => one
    [1] => two
    [2] => three
    [3] => (four, five, six)
    [4] => seven
    [5] => (eight, nine)
)

Doğrudan, yapamam. Minimum, değişken genişlikli Geriye bakan at, gerekiyordu, ve geçen PHP'nin PCRE'nin yalnızca sabit genişlikli gelmiştir Geriye bakan biliyordu.

Benim ilk öneri dizeden ilk özü parantez ifadeler olacaktır. Ama, gerçek sorun hakkında hiçbir şey bilmiyorum, bu yüzden bu mümkün olacak eğer ben bilmiyorum.

Tek bir regex kullanarak bunu yapmak için bir yol düşünemiyorum, ancak çalışır bir şey birlikte kesmek oldukça kolaydır:

function process($data)
{
        $entries = array();
        $filteredData = $data;
        if (preg_match_all("/\(([^)]*)\)/", $data, $matches)) {
                $entries = $matches[0];
                $filteredData = preg_replace("/\(([^)]*)\)/", "-placeholder-", $data);
        }

        $arr = array_map("trim", explode(",", $filteredData));

        if (!$entries) {
                return $arr;
        }

        $j = 0;
        foreach ($arr as $i => $entry) {
                if ($entry != "-placeholder-") {
                        continue;
                }

                $arr[$i] = $entries[$j];
                $j++;
        }

        return $arr;
}

Eğer bu gibi çağırmak:

$data = "one, two, three, (four, five, six), seven, (eight, nine)";
print_r(process($data));

Bu çıkışlar:

Array
(
    [0] => one
    [1] => two
    [2] => three
    [3] => (four, five, six)
    [4] => seven
    [5] => (eight, nine)
)

Sakar, ama iş yok ...

<?php

function split_by_commas($string) {
  preg_match_all("/\(.+?\)/", $string, $result); 
  $problem_children = $result[0];
  $i = 0;
  $temp = array();
  foreach ($problem_children as $submatch) { 
    $marker = '__'.$i++.'__';
    $temp[$marker] = $submatch;
    $string   = str_replace($submatch, $marker, $string);  
  }
  $result = explode(",", $string);
  foreach ($result as $key => $item) {
    $item = trim($item);
    $result[$key] = isset($temp[$item])?$temp[$item]:$item;
  }
  return $result;
}


$test = "one, two, three, (four, five, six), seven, (eight, nine), ten";

print_r(split_by_commas($test));

?>

Ben onun değerinde zaman muhtemelen her zaman düzenli ifadeler kaçınmak gerektiğini, belirterek hissediyorum. Bu amaçla, PHP 5.3 bilmeli + kullanmak olabilir str_getcsv(). Böyle CSV dosyaları gibi (veya dosya akışları), çalışıyorsanız Ancak, daha sonra işlevi fgetcsv() neye ihtiyacınız olacak, ve PHP4 beri mevcut olabilir.

Son olarak, preg_split() kullanılan şaşırdım kimse değilim, ya da gerektiği gibi işe yaramadı?