PHP تنفجر السلسلة، ولكن علاج الكلمات في علامات الاقتباس ككلمة واحدة

StackOverflow https://stackoverflow.com/questions/2202435

سؤال

كيف يمكنني تطبيق السلسلة التالية:

Lorem ipsum "dolor sit amet" consectetur "adipiscing elit" dolor

إلى

array("Lorem", "ipsum", "dolor sit amet", "consectetur", "adipiscing elit", "dolor")

بحيث يتم التعامل مع النص في اقتباس ككلمة واحدة.

إليك ما لدي الآن:

$mytext = "Lorem ipsum %22dolor sit amet%22 consectetur %22adipiscing elit%22 dolor"
$noquotes = str_replace("%22", "", $mytext");
$newarray = explode(" ", $noquotes);

لكن الرمز الخاص بي يقسم كل كلمة إلى صفيف. كيف أقوم بعمل الكلمات داخل علامات الاقتباس المعالجة ككلمة واحدة؟

هل كانت مفيدة؟

المحلول

يمكنك استخدام preg_match_all(...):

$text = 'Lorem ipsum "dolor sit amet" consectetur "adipiscing \\"elit" dolor';
preg_match_all('/"(?:\\\\.|[^\\\\"])*"|\S+/', $text, $matches);
print_r($matches);

والتي سوف تنتج:

Array
(
    [0] => Array
        (
            [0] => Lorem
            [1] => ipsum
            [2] => "dolor sit amet"
            [3] => consectetur
            [4] => "adipiscing \"elit"
            [5] => dolor
        )

)

وكما ترون، فإنه يمثل أيضا اقتباسات هربا من سلاسل ونقلت.

تعديل

شرح قصير:

"           # match the character '"'
(?:         # start non-capture group 1 
  \\        #   match the character '\'
  .         #   match any character except line breaks
  |         #   OR
  [^\\"]    #   match any character except '\' and '"'
)*          # end non-capture group 1 and repeat it zero or more times
"           # match the character '"'
|           # OR
\S+         # match a non-whitespace character: [^\s] and repeat it one or more times

وفي حالة المطابقة %22 بدلا من اقتباسات مزدوجة، كنت تفعل:

preg_match_all('/%22(?:\\\\.|(?!%22).)*%22|\S+/', $text, $matches);

نصائح أخرى

هذا سيكون أسهل بكثير مع str_getcsv().

$test = 'Lorem ipsum "dolor sit amet" consectetur "adipiscing elit" dolor';
var_dump(str_getcsv($test, ' '));

يعطيك

array(6) {
  [0]=>
  string(5) "Lorem"
  [1]=>
  string(5) "ipsum"
  [2]=>
  string(14) "dolor sit amet"
  [3]=>
  string(11) "consectetur"
  [4]=>
  string(15) "adipiscing elit"
  [5]=>
  string(5) "dolor"
}

يمكنك أيضا تجربة وظيفة Explode متعددة هذه

function multiexplode ($delimiters,$string)
{

$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return  $launch;
}

$text = "here is a sample: this text, and this will be exploded. this also | this one too :)";
$exploded = multiexplode(array(",",".","|",":"),$text);

print_r($exploded);

في بعض الحالات المعروفة قليلا token_get_all() قد تكون مفيدة:

$tokens = token_get_all("<?php $text ?>");
$separator = ' ';
$items = array();
$item = "";
$last = count($tokens) - 1;
foreach($tokens as $index => $token) {
    if($index != 0 && $index != $last) {
        if(count($token) == 3) {
            if($token[0] == T_CONSTANT_ENCAPSED_STRING) {
                $token = substr($token[1], 1, -1);
            } else {
                $token = $token[1];
            }
        }
        if($token == $separator) {
            $items[] = $item;
            $item = "";
        } else {
            $item .= $token;
        }
    }
}

نتائج:

Array
(
    [0] => Lorem
    [1] => ipsum
    [2] => dolor sit amet
    [3] => consectetur
    [4] => adipiscing elit
    [5] => dolor
)

جئت إلى هنا مع مشكلة تقسيم سلسلة معقدة مشابهة لهذا، ولكن لا شيء من الإجابات هنا فعلت بالضبط ما أردت - لذلك كتبت بلدي.

أقوم بنشرها هنا فقط في حال كان مفيدا لشخص آخر.

ربما تكون هذه طريقة بطيئة للغاية وغير فعالة للقيام بذلك - لكنها تعمل من أجلي.

function explode_adv($openers, $closers, $togglers, $delimiters, $str)
{
    $chars = str_split($str);
    $parts = [];
    $nextpart = "";
    $toggle_states = array_fill_keys($togglers, false); // true = now inside, false = now outside
    $depth = 0;
    foreach($chars as $char)
    {
        if(in_array($char, $openers))
            $depth++;
        elseif(in_array($char, $closers))
            $depth--;
        elseif(in_array($char, $togglers))
        {
            if($toggle_states[$char])
                $depth--; // we are inside a toggle block, leave it and decrease the depth
            else
                // we are outside a toggle block, enter it and increase the depth
                $depth++;

            // invert the toggle block state
            $toggle_states[$char] = !$toggle_states[$char];
        }
        else
            $nextpart .= $char;

        if($depth < 0) $depth = 0;

        if(in_array($char, $delimiters) &&
           $depth == 0 &&
           !in_array($char, $closers))
        {
            $parts[] = substr($nextpart, 0, -1);
            $nextpart = "";
        }
    }
    if(strlen($nextpart) > 0)
        $parts[] = $nextpart;

    return $parts;
}

الاستخدام كما يلي. explode_adv يأخذ 5 حجج:

  1. مجموعة من الشخصيات التي تفتح كتلة - على سبيل المثال [, (, ، إلخ.
  2. صفيف من الشخصيات التي تغلق كتلة - على سبيل المثال ], ), ، إلخ.
  3. مجموعة من الشخصيات التي تبديل كتلة - على سبيل المثال ", ', ، إلخ.
  4. مجموعة من الشخصيات التي يجب أن تتسبب في انقسام في الجزء التالي.
  5. السلسلة للعمل عليها.

هذه الطريقة ربما لها عيوب - التعديلات موضع ترحيب.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top