2013-08-19 2 views
2

У меня есть 100 файлов, каждый из которых содержит количество статей новостей. Статьи структурированы по разделам со следующими сокращениями:Как преобразовать структурированные текстовые файлы в многомерный массив PHP

HD BY WC PD SN SC PG LA CY LP TD CO IN NS RE IPC PUB AN 

где [LP] и [TD] может содержать любое количество пунктов.

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

HD Corporate News: Alcoa Earnings Soar; Outlook Stays Upbeat 
BY By James R. Hagerty and Matthew Day 
WC 421 words 
PD 12 July 2011 
SN The Wall Street Journal 
SC J 
PG B7 
LA English 
CY (Copyright (c) 2011, Dow Jones & Company, Inc.) 

LP 

Alcoa Inc.'s profit more than doubled in the second quarter, but the giant 
aluminum producer managed only to meet analysts' recently lowered forecasts. 

Alcoa serves as a bellwether for U.S. corporate earnings because it is the 
first major company to report and draws demand from a wide range of 
industries. 

TD 

The results marked an early test of how corporate optimism is holding up 
in the face of bleak economic news. 

License this article from Dow Jones Reprint 
Service[http://www.djreprints.com/link/link.html?FACTIVA=wjco20110712000115] 

CO 
almam : ALCOA Inc 

IN 
i2245 : Aluminum | i22 : Primary Metals | i224 : Non-ferrous Metals | imet 
    : Metals/Mining 

NS 
c15 : Performance | c151 : Earnings | c1521 : Analyst 
Comment/Recommendation | ccat : Corporate/Industrial News | c152 : 
Earnings Projections | ncat : Content Types | nfact : Factiva Filters | 
nfce : FC&E Exclusion Filter | nfcpin : FC&E Industry News Filter 

RE 
usa : United States | use : Northeast U.S. | uspa : Pennsylvania | namz : 
North America 

IPC 
DJCS | EWR | BSC | NND | CNS | LMJ | TPT 

PUB 
Dow Jones & Company, Inc. 

AN 
Document J000000020110712e77c00035 

После каждой статьи есть 4 строк до начала новой статьи. Мне нужно поставить эти статьи в массив следующим образом:

$articles = array(
    [0] = array (
    [HD] => Corporate News: Alcoa earnings Soar; Outlook... 
    [BY] => By James R. Hagerty... 
    ... 
    [AN] => Document J000000020110712e77c00035 
) 
) 

[edit] Благодаря @Casimir и др Ипполит теперь у меня есть:

$path = "C:/path/to/textfiles/"; 

if ($handle = opendir($path)) { 
    while (false !== ($file = readdir($handle))) { 
    if ('.' === $file) continue; 
    if ('..' === $file) continue; 

    $text = file_get_contents($path . $file); 
    $subjects = explode("\r\n\r\n\r\n\r\n", $text); 

    $pattern = <<<'LOD' 
     ~ 
     # definition 
     (?(DEFINE)(?<fieldname>(?<=^|\n)(?>HD|BY|WC|PD|SN|SC|PG|LA|CY|LP|TD|CO|IN|NS|RE|IPC|PUB|AN))) 
     # pattern 
     \G(?<key>\g<fieldname>)\s++(?<value>[^\n]++(?>\n{1,2}+(?!\g<fieldname>) [^\n]++)*+)(?>\n{1,3}|$) 
     ~x 
LOD; 

    $result = array(); 
    foreach($subjects as $i => $subject) { 
     if (preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)) { 
     foreach ($matches as $match) { 
      $result[$i][$match['key']] = $match['value']; 
     } 
     } 
    } 
    } 
    closedir($handle); 
    echo '<pre>'; 
    print_r($result); 
} 

Однако никаких совпадений не были найдены, ни какие-либо ошибки производятся. Может кто-нибудь спросить меня, что здесь не так?

+0

(http://mattgemmell.com/2008/ 12/08/what-have-you-try /) –

ответ

3

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

$pattern = <<<'LOD' 
~ 
# definition 
(?(DEFINE) 
    (?<fieldname> (?<=^|\n) 
        (?>HD|BY|WC|PD|SN|SC|PG|LA|CY|LP|TD|CO|IN|NS|RE|IPC|PUB|AN) 
    ) 
) 

# pattern 
\G(?<key>\g<fieldname>) \s++ 
(?<value> 
    [^\n]++ 
    (?> \n{1,2}+ (?!\g<fieldname>) [^\n]++)*+ 
) 
(?>\n{1,3}|$) 
~x 
LOD; 
$subjects = explode("\n\n\n\n", $text); 
$result = array(); 

foreach($subjects as $i=>$subject) { 
    if (preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)) { 
     foreach ($matches as $match) { 
      $result[$i][$match['key']]=$match['value']; 
     } 
    } 
} 
echo '<pre>'; 
print_r($result); 

Pattern Детали:

Схема разделена на две части:

  • определения: где вы можете написать подшаблоны для использования позже
  • patte гп себе

В части определения я пишу подшаблон по имени имя_поля где я положил все имена полей и состояние в начале. Условие проверяет, предшествует ли fiedname началу строки (^) или новой строке (\n), чтобы избежать захвата одинаковых букв внутри абзаца, например.

Описание шаблона части:

\G      # this forces the match to be contiguous to the 
          # precedent match or the start of the string (no gap) 
(?<key> \g<fieldname>) # a capturing group named "key" for the fieldname 
\s++      # one or more white characters 
(?<value>     # open a capturing group named "value" for the 
          # field content 
    [^\n]++    # all characters except newlines 1 or more times 
    (?>     # open an atomic group 
     \n{1,2}+   # one or two newlines to allow paragraphs (LP & TD) 
     (?!\g<fieldname>) # but not followed by a fieldname (only a check) 
     [^\n]++   # all characters except newlines 1 or more times 
    )*+     # close the atomic group and repeat 0 or more times 
)       # close the capture group "value" 
(?>\n{1,3}|$)    # between 1 or 3 newlines max. or the end of the 
          # string (necessary if i want contiguous matches) 

x в конце $ шаблона позволяет многословным режим в регулярных выражениях (вы можете поместить комментарии внутрь с #, и вы можете форматировать код, вы хотите с пробелами).

Примечание: этот шаблон не заботится о порядке полей и если они присутствуют или нет. Для большей читаемости, я использую nowdoc syntax (<<<'ABC'), чтобы быть осторожным, чтобы использовать его правильно.

Если текстовый файл имеет формат окна для переноса строк (т.е. \r\n), вы должны изменить рисунок на: [? То, что вы пытались]

$pattern = <<<'LOD' 
~ 
# definition 
(?(DEFINE) 
    (?<fieldname> (?<=^|\n) 
        (?>HD|BY|WC|PD|SN|SC|PG|LA|CY|LP|TD|CO|IN|NS|RE|IPC|PUB|AN) 
    ) 
) 

# pattern 
\G(?<key>\g<fieldname>) \s++ 
(?<value> 
    [^\r\n]++ 
    (?> (?>\r?\n){1,2}+ (?!\g<fieldname>) [^\r\n]++)*+ 
) 
(?>(?>\r?\n){1,3}|$) 
~x 
LOD; 
$subjects = explode("\r\n\r\n\r\n\r\n", $text); 
+0

Возможно, вы захотите ссылаться на строковое цитирование Heredoc. Если кто-то вставляет это в нечто вроде Dreamweaver, у него будут всевозможные ошибки.http://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc –

+0

Спасибо! Но выполнение этого для примера в TS возвращает нулевые совпадения. '$ subject' содержит один документ (как указано в $ text из TS), но шаблон не соответствует чему-либо? – Pr0no

+1

@ Pr0no: Я тестировал с помощью Text Sample, и он хорошо работает. Я отправлю образец данных. –