2015-11-20 2 views
3

У меня есть текстовый файл, который хранит информацию о разных элементах.PHP разбор пользовательской плоской текстовой базы данных

Этот файл является структурированным. Каждый элемент в файле разделяется фигурными фигурными скобками {} и обрабатывается запятой. Каждый элемент имеет список атрибутов, которые он имеет, и атрибуты могут быть там или нет. Если их там нет, сервер предполагает, что они «по умолчанию».

Каждая запись в фигурные скобки и заканчивается запятой: {}, Файл также включает в себя стандартный C комментирование, // наряду с/* */ Каждый атрибут элемента стандартизирован из пула 33 атрибуты, только 3 из которых являются обязательными. Атрибуты могут быть включены или исключены. Предполагается, что атрибуты, которые не включены, по умолчанию относятся к базовой программе. Есть несколько атрибутов, которые могут быть многострочными или даже мультиатрибутными (формируя массив, если хотите).

Итак, файл примерно выглядит следующим образом:

itemdb: (
/* 
{  
    Multi line comment 
    here to explain the file 
    }, 
    */ 
    // Here starts the items 
    { 
    Id: 500 
    DatabaseName: "Item_1" 
    Name: "Item 1" 
    Type: 1 
    Buy: 40 
    Weight: 10 
    }, 
    { 
    Id: 501 
    DatabaseName: "Item_2" 
    Name: "Item 2" 
    Type: 1 
    Sell: 600 
    Weight: 200 
    Script: <" do stuff; "> 
    }, 
    // Here is some more items 
    { 
    Id: 637 
    DatabaseName: "Item_137" 
    Name: "Item 137" 
    Type: 5 
    Buy: 9000 
    Weight: 300 
    Trade: { 
     nodrop: true 
     notrade: true 
    } 
    Script: <" 
       do this stuff; 
       then this stuff; 
       "> 
}, 
// Note: Edited this in 2015-11-23, see below. 
) 

Мне нужен способ, чтобы разбить все элементы в массив для отображения пользователю. Массив будет выглядеть примерно так (как в примере выше):

$itemDB = Array 
(
    [500] => Array 
    (
     [DatabaseName] => Item_1 
     [Name] => Item 1 
     [Type] => 1 
     [Buy] => 40 
     [Weight] => 10 
    ) 
    [501] => Array 
    (
     [DatabaseName] => Item_2 
     [Name] => Item 2 
     [Type] => 1 
     [Sell] => 600 
     [Weight] => 200 
     [Script] => do stuff 
    ) 
    [637] => Array 
    (
     [DatabaseName] => Item_137 
     [Name] => Item 137 
     [Type] => 5 
     [Buy] => 9000 
     [Weight] => 300 
     [Trade] => array 
     (
     [nodrop] => true 
     [notrade] => true 
    ) 
     [Script] => do this stuff;\nthen this stuff 
    ) 
); 

(так в основном разбить файл в многомерный массив с помощью атрибута «Id» из файла, ключ каждого массива и каждый атрибут файл является его собственный ключ/значение)

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

$ready = str_replace(array("{","}"),"|", $itemDB); 
$itemDB_explode = explode("|", $ready); 

Этот код, однако, только получает меня на полпути. Я в основном приходят с массивом, как это:

[7]=> string(124) " Id: 501 DatabaseName: "Item_2" Name: "Item 2" Type: 1 Sell: 600 Weight: 200 Script: <" do stuff "> " 

Но для жизни меня я не могу понять, как получить его дальше, чем это, в том числе, как сделать ключ массива идентификатор и каждый атрибут имеет свой собственный ключ/значение.

Цель состоит в том, чтобы отобразить запись для пользователя, разрешить им вносить изменения и затем сохранять файл обратно. Надеюсь, я смогу также помочь в спасении.

для тех, кто, несомненно, спросит: да, я знаю, что что-то вроде этого лучше подходит для базы данных SQL. Проблема в том, что этот файл и бэкенд читать и интерпретировать его не написаны мной, и я не могу изменить его. Я просто пишу веб-интерфейс, чтобы легко изменить этот файл.

Благодарим вас за помощь, которую вы можете предоставить.

Редактировать 2015-11-23: Я оставил некоторые атрибуты от моего первоначального вопроса. Рассмотрим это изменение в реальный файл с недостающих атрибутов добавил:

{ 
    Id: 845 
    DatabaseName: "Item_345" 
    Name: "Item 345" 
    Type: 3 
    Buy: 30000 
    Nouse: { 
    override: 30 
    sitting: true 
    } 
    Stack: [99, 4] 
    OnEquipScript: <" do this stuff; "> 
    OnUnequipScript: <" 
       do some more stuff; 
       this is some more stuff; 
         "> 
}, 

Рассмотрим, что результирующий массив будет выглядеть для этого дополнительного блока в файле:

[845] => Array 
    (
     [DatabaseName] => Item_345 
     [Name] => Item 345 
     [Type] => 3 
     [Buy] => 30000 
     [Nouse] => array 
     (
     [override] => 30 
     [sitting] => true 
    ) 
     [Stack] => 
     (
     [0] => 99 
     [1] => 4 
    ) 
     [OnEquipScript] => do this stuff; 
     [OnUnequipScript] => do some more stuff;\nthis is some more stuff; 
    ) 

ответ

3

Мысль я мог постучать это прочь в 15 минут, пока я сидел на удержании, но многострочный скрипт застрял в конце.Так что потребовалось 35 минут вместо этого, но могу вас заверить, вы не были на полпути;)

<?php 

$items = array(); 
$in_comment = false; 
$in_trade = false; 
$in_script = false; 

$itemDB = file("foo.txt"); 

foreach ($itemDB as $row) { 
    $row = trim($row); 
    if (strpos($row, "//") === 0) continue; 
    if (strpos($row, "/*") === 0) { 
     $in_comment = true; 
     continue; 
    } 
    if (strpos($row, "*/") === 0) { 
     $in_comment = false; 
     continue; 
    } 
    if ($in_comment) continue; 
    if ($row === "itemdb: (") continue; 
    if ($row === ")") continue; 
    if (strpos($row, "{") === 0) { 
     $item = array(); 
    } 
    elseif (!$in_trade && strpos($row, "}") === 0) { 
     $items[$item["Id"]] = $item; 
    } else { 
     $row = explode(":", $row); 
     $key = trim($row[0]); 
     $val = isset($row[1]) ? trim($row[1]) : ""; 
     if ($key === "Trade" && strpos($val, "{") === 0) { 
      $in_trade = true; 
      $item["Trade"] = array(); 
      continue; 
     } elseif ($in_trade && $key === "}") { 
      $in_trade = false; 
      continue; 
     } elseif ($key === "Script") { 
      $in_script = true; 
      $item["Script"] = ""; 
     } 

     if ($in_trade) { 
      $item["Trade"][$key] = $val; 
     } elseif ($in_script) { 
      $item["Script"] .= (empty($val) ? $key : $val) . "\n"; 
      if (strpos($key, "\">") !== false || strpos($val, "\">") !== false) { 
       $item["Script"] = str_replace(array("<\"", "\">"), "", $item["Script"]); 
       $item["Script"] = trim($item["Script"]); 
       $in_script = false; 
      } 
     } else { 
      $item[$key] = $val; 
     } 
    } 
} 

print_r($items); 
+0

Удивительно, спасибо за код! Тем не менее, я провел несколько тестов с ним и скопировал именно то, что у вас есть. Я убедился, что путь к моему файлу действителен и работает. Я использовал 'print_r ($ itemDB);' после загрузки файла в $ itemDB, и каждая строка файла выходит в свой собственный элемент массива, как это делает ваш код, но в конце '$ items' просто приходит к пустому массиву. – Jguy

+0

А, я думаю, я знаю, почему, или, возможно, почему. В исходном файле есть еще несколько атрибутов, которые я даже не видел или не включал в свой первоначальный вопрос. Я отредактирую их, но я думаю, что у меня есть довольно хорошая ручка, что он собирается предпринять, чтобы заставить это работать. – Jguy

+0

Все, что я могу сказать, это сработало для меня с образцами данных, которые вы дали. Он делает некоторые предположения, основанные на вашем примере кода. А именно, что комментарии начинаются и заканчиваются в начале строки, а также с каждым разделителем элементов. Как вы можете видеть, триггер для заполнения '$ items' текущим' $ item' находит '' 'как первый символ в строке. – miken32