извлечение текста из файла для просмотра - в нестандартном формате - php - PullRequest
0 голосов
/ 21 февраля 2012

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

"Stranglehold"
Written by Ted Nugent
Performed by Ted Nugent
Courtesy of Epic Records
By Arrangement with
Sony Music Licensing
"Chateau Lafltte '59 Boogie"
Written by David Peverett
and Rod Price
Performed by Foghat
Courtesy of Rhino Entertainment
Company and Bearsville Records
By Arrangement with
Warner Special Products

Мне нужен только заголовок песни (информация между кавычками), кому она написана и кем она исполняется.Как видите, написанные строки могут содержать более одной строки.

Я искал вопросы, и этот вопрос похож на Очистка простого текстового файла без HTML? , и я смог изменить решение https://stackoverflow.com/a/8432563/827449 ниже так, чтобыон по крайней мере найдет информацию между кавычками и поместит их в массив.Однако я не могу понять, где и как поместить следующие операторы preg_match для написанного и выполненного таким образом, чтобы он добавил его в массив с правильной информацией, если, конечно, у меня есть правильное регулярное выражение.Вот модифицированный код.

<?php
$in_name = 'in.txt';
$in = fopen($in_name, 'r') or die();

function dump_record($r) {
    print_r($r);
}
    $current = array();
    while ($line = fgets($fh)) {

        /* Skip empty lines (any number of whitespaces is 'empty' */
        if (preg_match('/^\s*$/', $line)) continue;

        /* Search for 'things between quotes' stanzas */
        if (preg_match('/(?<=\")(.*?)(?=\")/', $line, $start)) {
            /* If we already parsed a record, this is the time to dump it */
            if (!empty($current)) dump_record($current);

        /* Let's start the new record */
        $current = array( 'id' => $start[1] );
    }
    else if (preg_match('/^(.*):\s+(.*)\s*/', $line, $keyval)) {
        /* Otherwise parse a plain 'key: value' stanza */
        $current[ $keyval[1] ] = $keyval[2];
    }
    else {
        error_log("parsing error: '$line'");
    }
}
/* Don't forget to dump the last parsed record, situation
 * we only detect at EOF (end of file) */
if (!empty($current)) dump_record($current);

fclose($in);

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

Ответы [ 2 ]

1 голос
/ 21 февраля 2012

Как насчет:

$str =<<<EOD
"Stranglehold"
Written by Ted Nugent
Performed by Ted Nugent
Courtesy of Epic Records
By Arrangement with
Sony Music Licensing
"Chateau Lafltte '59 Boogie"
Written by David Peverett
and Rod Price
Performed by Foghat
Courtesy of Rhino Entertainment
Company and Bearsville Records
By Arrangement with
Warner Special Products

EOD;

preg_match_all('/"([^"]+)".*?Written by (.*?)Performed by (.*?)Courtesy/s', $str, $m, PREG_SET_ORDER);
print_r($m);

выход:

Array
(
    [0] => Array
        (
            [0] => "Stranglehold"
Written by Ted Nugent
Performed by Ted Nugent
Courtesy
            [1] => Stranglehold
            [2] => Ted Nugent

            [3] => Ted Nugent

        )

    [1] => Array
        (
            [0] => "Chateau Lafltte '59 Boogie"
Written by David Peverett
and Rod Price
Performed by Foghat
Courtesy
            [1] => Chateau Lafltte '59 Boogie
            [2] => David Peverett
and Rod Price

            [3] => Foghat

        )

)
1 голос
/ 21 февраля 2012

Вот регулярное выражение решения проблемы.Имейте в виду, что вам не нужно регулярное выражение здесь.См. Второй вариант ниже.

<?php

$string = '"Stranglehold"
Written by Ted Nugent
Performed by Ted Nugent
Courtesy of Epic Records
By Arrangement with
Sony Music Licensing
"Chateau Lafltte \'59 Boogie"
Written by David Peverett
and Rod Price
Performed by Foghat
Courtesy of Rhino Entertainment
Company and Bearsville Records
By Arrangement with
Warner Special Products';

// Titles delimit a record
$title_pattern = '#"(?<title>[^\n]+)"\n(?<meta>.*?)(?=\n"|$)#s';
// From the meta section we need these tokens
$meta_keys = array(
    'Written by ' => 'written',
    'Performed by ' => 'performed',
    'Courtesy of ' => 'courtesy',
    "By Arrangement with\n" => 'arranged',
);
$meta_pattern = '#(?<key>' . join(array_keys($meta_keys), "|") . ')(?<value>[^\n$]+)(?:\n|$)#ims';


$songs = array();
if (preg_match_all($title_pattern, $string, $matches, PREG_SET_ORDER)) {
    foreach ($matches as $match) {
        $t = array(
            'title' => $match['title'],
        );

        if (preg_match_all($meta_pattern, $match['meta'], $_matches, PREG_SET_ORDER)) {
            foreach ($_matches as $_match) {
                $k = $meta_keys[$_match['key']];
                $t[$k] = $_match['value'];
            }
        }

        $songs[] = $t;
    }
}

приведет к

$songs = array (
  array (
    'title'     => 'Stranglehold',
    'written'   => 'Ted Nugent',
    'performed' => 'Ted Nugent',
    'courtesy'  => 'Epic Records',
    'arranged'  => 'Sony Music Licensing',
  ),
  array (
    'title'     => 'Chateau Lafltte \'59 Boogie',
    'written'   => 'David Peverett',
    'performed' => 'Foghat',
    'courtesy'  => 'Rhino Entertainment',
    'arranged'  => 'Warner Special Products',
  ),
);

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

<?php

$string = '"Stranglehold"
Written by Ted Nugent
Performed by Ted Nugent
Courtesy of Epic Records
By Arrangement with
Sony Music Licensing
"Chateau Lafltte \'59 Boogie"
Written by David Peverett
and Rod Price
Performed by Foghat
Courtesy of Rhino Entertainment
Company and Bearsville Records
By Arrangement with
Warner Special Products';

$songs = array();
$current = array();
$lines = explode("\n", $string);
// can't use foreach if we want to extract "By Arrangement"
// cause it spans two lines
for ($i = 0, $_length = count($lines); $i < $_length; $i++) {
    $line = $lines[$i];
    $length = strlen($line); // might want to use mb_strlen()

    // if line is enclosed in " it's a title
    if ($line[0] == '"' && $line[$length - 1] == '"') {
        if ($current) {
            $songs[] = $current;
        }

        $current = array(
            'title' => substr($line, 1, $length - 2),
        );

        continue;
    }

    $meta_keys = array(
        'By Arrangement with' => 'arranged', 
    );

    foreach ($meta_keys as $key => $k) {
        if ($key == $line) {
            $i++;
            $current[$k] = $lines[$i];
            continue;
        }
    }

    $meta_keys = array(
        'Written by ' => 'written', 
        'Performed by ' => 'performed', 
        'Courtesy of ' => 'courtesy',
    );

    foreach ($meta_keys as $key => $k) {
        if (strpos($line, $key) === 0) {
            $current[$k] = substr($line, strlen($key));
            continue 2;
        }
    }    
}

if ($current) {
    $songs[] = $current;
}
...