PHP: преобразовать строку объекта javascript в массив php

#javascript #php #regex #parsing

#javascript #php #регулярное выражение #синтаксический анализ

Вопрос:

Я получаю одну страницу html-кода с помощью phpQuery, а затем получаю приведенный ниже строковый код из тега script в head через php regex:

 var BASE_DATA = {
userInfo: {
  id: 0,
  userName: 'no-needed',
  avatarUrl: 'no-needed',
  isPgc: false,
  isOwner: false
},
headerInfo: {
  id: 0,
  isPgc: false,
  userName: 'no-needed',
  avatarUrl: 'no-needed',
  isHomePage: false,
  crumbTag: 'no-needed',
  hasBar: true
},
articleInfo: 
{
  title: 'needed',
  content: 'needed',
  groupId: 'needed',
  itemId: 'needed',
  type: 1,
  subInfo: {
    isOriginal: false,
    source: 'needed',
    time: 'needed'
  },
  tagInfo: {
    tags: [{"name":"no-needed 1"},{"name":"no-needed 2"},{"name":"no-needed 3"}],
    groupId: 'no-needed',
    itemId: 'no-needed',
    repin: 0,
  },
  has_extern_link: 0,
  coverImg: 'no-needed'
},
commentInfo:
{
  groupId: 'no-needed',
  itemId: 'no-needed',
  comments_count: 151,
  ban_comment: 0
},};
 

Я хочу преобразовать эту строку в массив php, например:

 $base_data = array(
'articleInfo' => array(
    'title' => 'needed',
    'content' => 'needed',
    'groupId' => 'needed',
    'itemId' => 'needed',
    'subInfo' => array(
        'source' => 'needed',
        'time' => 'needed',
    ),
));
 

или

 $base_data = array(
'title' => 'needed',
'content' => 'needed',
'groupId' => 'needed',
'itemId' => 'needed',
'subInfo' => array(
    'source' => 'needed',
    'time' => 'needed',
),);
 

Я уже пробовал многими способами, такими как: json_decode, получение содержимого из фигурных скобок с помощью регулярного выражения php и функции preg_match_all.Но все они работают плохо.

Я пробовал два способа:

первый способ:

 $json = str_ireplace(array('var BASE_DATA =', '};'), array('', '}'), $js);
json_decode($json, true);
 

второй способ:

 preg_match_all('/{([^}] )}/', $js, $matches);
print_r($matches[1]);
 

или

 preg_match_all('/articleInfo:s*{([^}] )}/', $script_text, $matches);
print_r($matches[1][0]);
 

Кажется, что он близок к завершению, но он по-прежнему выглядит неважно, мне нужно проанализировать строку в части articleInfo …. вот почему я опубликовал этот пост.

Я даже хотел использовать движок JavaScript V8, но…..

кто-нибудь знает лучший способ закончить это, пожалуйста?

Комментарии:

1. Если исходная строка содержит var BASE_DATA = часть, вы не сможете ее json_decode, пока не удалите ее. Конечная запятая в конце также является проблемой, и она может жаловаться или не жаловаться на самую последнюю точку с запятой. Не уверен в этом отношении, насколько простителен json_decode.

2. да, я уже обнаружил эту проблему, поэтому я уже пробовал с str_ireplace(array(‘var BASE_DATA =’, ‘};’), array(«, ‘}’), $js); но я знаю, что мне делать дальше. на самом деле, я также пробовал: preg_match_all(‘/{([^}] )}/’, $ js, $matches); Кажется, он близок к завершению, но все равно выглядит неважно, я должен проанализировать строку в части articleInfo …. вот почемуЯ опубликовал этот пост.

3. «Я уже пробовал многими способами» скажите…

4. @miken32 Я отредактировал, пожалуйста, проверьте

Ответ №1:

Мне пришлось переформатировать ваш JSON, который был недействительным (проверено на https://jsonlint.com /).

Я добровольно использовал несколько str_replace(), чтобы вы лучше понимали процесс, однако вы можете оптимизировать приведенный ниже код, сделав несколько замен одновременно в одном str_replace() .

Это работает:

 <?php

$to_decode = "var BASE_DATA = {
userInfo: {
  id: 0,
  userName: 'no-needed',
  avatarUrl: 'no-needed',
  isPgc: false,
  isOwner: false
},
headerInfo: {
  id: 0,
  isPgc: false,
  userName: 'no-needed',
  avatarUrl: 'no-needed',
  isHomePage: false,
  crumbTag: 'no-needed',
  hasBar: true
},
articleInfo: 
{
  title: 'needed',
  content: 'needed',
  groupId: 'needed',
  itemId: 'needed',
  type: 1,
  subInfo: {
    isOriginal: false,
    source: 'needed',
    time: 'needed'
  },
  tagInfo: {
    tags: [{"name":"no-needed 1"},{"name":"no-needed 2"},{"name":"no-needed 3"}],
    groupId: 'no-needed',
    itemId: 'no-needed',
    repin: 0,
  },
  has_extern_link: 0,
  coverImg: 'no-needed'
},
commentInfo:
{
  groupId: 'no-needed',
  itemId: 'no-needed',
  comments_count: 151,
  ban_comment: 0
},};";

/* Clean JSON and encapsulate in brackets */
$to_decode = str_replace('var BASE_DATA = {', '', $to_decode);
$to_decode = '{'.substr($to_decode, 0, -3).'}';

/* Remove spaces, tabs, new lines, etc. */
$to_decode = str_replace(' ', '', $to_decode);
$to_decode = str_replace("n", '', $to_decode);
$to_decode = str_replace("t", '', $to_decode);
$to_decode = str_replace("r", '', $to_decode);

/* Encapsulate keys with quotes */
$to_decode = preg_replace('/([a-z_] ):/ui', '"{$1}":', $to_decode);
$to_decode = str_replace('"{', '"', $to_decode);
$to_decode = str_replace('}"', '"', $to_decode);
$to_decode = str_replace(''', '"', $to_decode);

/* Remove unecessary trailing commas */
$to_decode = str_replace(',}', '}', $to_decode);

echo '<pre>';
var_dump(json_decode($to_decode));
 

Результат с использованием print_r :

(Я добавил true / false для ясности, в противном случае они будут отображаться только с использованием var_dump())

 stdClass Object
(
    [userInfo] => stdClass Object
        (
            [id] => 0
            [userName] => no-needed
            [avatarUrl] => no-needed
            [isPgc] => false
            [isOwner] => false
        )

    [headerInfo] => stdClass Object
        (
            [id] => 0
            [isPgc] => false
            [userName] => no-needed
            [avatarUrl] => no-needed
            [isHomePage] => false
            [crumbTag] => no-needed
            [hasBar] => true
        )

    [articleInfo] => stdClass Object
        (
            [title] => needed
            [content] => needed
            [groupId] => needed
            [itemId] => needed
            [type] => 1
            [subInfo] => stdClass Object
                (
                    [isOriginal] => false
                    [source] => needed
                    [time] => needed
                )

            [tagInfo] => stdClass Object
                (
                    [tags] => Array
                        (
                            [0] => stdClass Object
                                (
                                    [name] => no-needed1
                                )

                            [1] => stdClass Object
                                (
                                    [name] => no-needed2
                                )

                            [2] => stdClass Object
                                (
                                    [name] => no-needed3
                                )

                        )

                    [groupId] => no-needed
                    [itemId] => no-needed
                    [repin] => 0
                )

            [has_extern_link] => 0
            [coverImg] => no-needed
        )

    [commentInfo] => stdClass Object
        (
            [groupId] => no-needed
            [itemId] => no-needed
            [comments_count] => 151
            [ban_comment] => 0
        )

)
 

Ответ №2:

спасибо @Bruno Leveque за вашу идею.

Я отредактировал ваш код, как показано ниже, чтобы он работал хорошо:

  1. Я изменил $to_decode = str_replace(' ', '', $to_decode); на $to_decode = preg_replace('/[n| |s]{2,}/',' ',$to_decode); , это означает, что все 1 пробел будет изменен на 1 пробел. потому что иногда нам нужно пространство, например: content: ‘
  2. Я добавил $to_decode = str_replace("'", '"', $to_decode); перед вашим комментарием код /* Encapsulate keys with quotes */
  3. изменено $to_decode = preg_replace('/([a-z_] ):/ui', '"{$1}":', $to_decode); на $to_decode = preg_replace('/([a-z_] ): /ui', '"$1":', $to_decode); (там еще один пробел); и прокомментировал //$to_decode = str_replace('"{', '"', $to_decode); и //$to_decode = str_replace('}"', '"', $to_decode);
  4. добавлен еще один код: $to_decode = str_replace(", }", '}', $to_decode);

итак, мой окончательный код :введите описание изображения здесь

поскольку @Bruno Leveque не знает точного содержания «необходимо» и «не требуется», так что спасибо за идею.

кажется, это не идеальный способ….