PHP читает первые 2 строки файла в переменную и проходит через подпапки - PullRequest
1 голос
/ 17 декабря 2011

Я пытаюсь сделать следующее с PHP ...

  1. Читать каталог
  2. Найти все .md и .markdown files
  3. Прочитайте первые 2 строки этих файлов Markdown.
  4. Если в line 1 найден Title: Title for the file, то добавьте его в массив
  5. Если в строке 2 найдено Description: Short description, добавьте его в массив
  6. Если подкаталог найден, повторите шаги 1-5 для них
  7. Теперь у вас должен быть красивый список / массив
  8. Распечатайте этот список / массив на экран, чтобы отобразиться так ...

Directory 1 Name

<a href="LINK TO MARKDOWN FILE 1"> TITLE from line 1 of Markdown FILE 1</a> <br>
Description from Markdown FILE 1 line 2

<a href="LINK TO MARKDOWN FILE 2"> TITLE from line 1 of Markdown FILE 1</a> <br>
Description from Markdown FILE 2 line 2

<a href="LINK TO MARKDOWN FILE 3"> TITLE from line 1 of Markdown FILE 1</a> <br>
Description from Markdown FILE 3 line 2

Directory 2 Name

<a href="LINK TO MARKDOWN FILE 1"> TITLE from line 1 of Markdown FILE 1</a> <br>
Description from Markdown FILE 1 line 2

<a href="LINK TO MARKDOWN FILE 2"> TITLE from line 1 of Markdown FILE 1</a> <br>
Description from Markdown FILE 2 line 2

<a href="LINK TO MARKDOWN FILE 3"> TITLE from line 1 of Markdown FILE 1</a> <br>
Description from Markdown FILE 3 line 2

etc..........

Код до сих пор

function getFilesFromDir($dir)
{
    $files = array();
    //scan directory passsed into function
    if ($handle = opendir($dir)) {
        while (false !== ($file = readdir($handle))) {

            // If file is .md or .markdown continue
            if (preg_match('/\.(md|markdown)$/', $file)) {

                // Grab first 2 lines of Markdown file
                $content = file($dir . '/' . $file);
                $title = $content[0];
                $description = $content[1];

                // If first 2 lines of Markdown file have a 
                // "Title: file title" and "Description: file description" lines we then
                // add these key/value pairs to the array for meta data

                // Match Title line
                $pattern = '/^(Title|Description):(.+)/';
                if (preg_match($pattern, $title, $matched)) {
                    $title = trim($matched[2]);
                }

                // match Description line 
                if (preg_match($pattern, $description, $matched)) {
                    $description = trim($matched[2]);
                }

                // Add .m and .markdown files and folder path to array
                // Add captured Title and Description to array as well
                $files[$dir][] = array("filepath" => $dir . '/' . $file,
                                       "title" => $title,
                                       "description" => $description
                                    );

            }
        }
        closedir($handle);
    }

    return $files;
}

Использование

$dir = 'mdfiles';
$fileArray = getFilesFromDir($dir);

Требуется помощь

Пока что коду нужно просто добавить возможность делать то, что он делаетна подкаталоги и способ, которым он соответствует первым 2 строкам кода, а затем запускает регулярное выражение 2 раза, возможно, можно сделать по-другому?

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

Может кто-нибудь помочь мне изменить, чтобы этот код обнаружил и запустилв подкаталогах, а также улучшить способ чтения первых двух строк файла уценки, чтобы получить заголовок и описание, если они существуют?

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

Я ценю любую помощь

Ответы [ 2 ]

2 голосов
/ 17 декабря 2011

Для рекурсивной итерации по файлам RecursiveDirectoryIterator очень удобен (относится: Путь к рекурсивной директории PHP ).Он также предлагает простой доступ к FileSystemObject, что выглядит полезным в вашем случае, так как вы хотите получить содержимое файлов.

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

#
# configuration
#

$path = 'md';
$fileFilter = '~\.(md|markdown)$~';
$pattern = '~^(?:Title: (.*))?(?:(?:\r\n|\n)(?:Description: (.*)))?~u';

На всякий случай, если файлы разметки на самом деле кодируются в UTF-8, я добавил модификатор u (PCRE8).

Обрабатывающая частьзатем код использует рекурсивный итератор каталога над $path, пропускает файлы, не соответствующие $fileFilter, а затем анализирует первые две строки каждого файла (если файл по крайней мере читаем и имеет хотя бы одну строку) и сохраняет его вхеш-таблица на основе каталога / массив $result:

#
# main
#

# init result array (the nice one)
$result = array();

# recursive iterator for files
$iterator = new RecursiveIteratorIterator(
               new RecursiveDirectoryIterator($path, FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO), 
               RecursiveIteratorIterator::SELF_FIRST);

foreach($iterator as $path => $info)
{
    # filter out files that don't match
    if (!preg_match($fileFilter, $path)) continue;

    # get first two lines
    try
    {
        for
        (
            $maxLines = 2,
            $lines = '',
            $file = $info->openFile()
            ; 
            !$file->eof() && $maxLines--
            ; 
            $lines .= $file->fgets()
        );
        $lines = rtrim($lines, "\n");

        if (!strlen($lines)) # skip empty files 
            continue;
    }
    catch (RuntimeException $e)
    {
        continue; # files which are not readable are skipped.
    }

    # parse md file
    $r = preg_match($pattern, $lines, $matches);
    if (FALSE === $r)
    {
        throw new Exception('Regular expression failed.');
    }
    list(, $title, $description) = $matches + array('', '', '');

    # grow result array
    $result[dirname($path)][] = array($path, $title, $description);
}

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

#
# output
#

$dirCounter = 0;
foreach ($result as $name => $dirs)
{
    printf("Directory %d %s\n", ++$dirCounter, basename($name));
    foreach ($dirs as $entry)
    {
        list($path, $title, $description) = $entry;
        printf("<a href='%s'>%s from line 1 of Markdown %s</a> <br>\n%s\n\n", 
                htmlspecialchars($path), 
                htmlspecialchars($title),               
                htmlspecialchars(basename($path)),
                htmlspecialchars($description)
              );
    }
}
1 голос
/ 17 декабря 2011

Это должно сработать:

if (preg_match('/\.(md|markdown)$/', $file)) {
   // ...
} elseif (is_dir($file)) {
    $files = array_merge($files, getFilesFromDir($dir . '/' . $file));
}

Выполнение регулярного выражения дважды не так уж и плохо, и может быть лучше, чем попытка что-то объединить в обе строки.Однако вы можете достичь того же результата с помощью preg_replace:

$title = trim(preg_replace('/^Title:(.+)/', '$1', $content[0]));
$description = trim(preg_replace('/^Description:(.+)/', '$1', $content[1]));

Для вывода массива в соответствии с примером это:

foreach ($filesArray as $directory => $files) {
    echo $directory . "\n\n";

    foreach ($files as $fileData) {
        echo '<a href="' . $fileData['filepath'] . '">' . $fileData['title'] . "</a><br />\n";
        echo $fileData['description'] . "\n\n";
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...