Как снять диапазон элементов цикла for с помощью PHP?

0

Пример:

@article{boonzaier2009development,<br/>
 author = "Boonzaier, A. and Schubach, K. and Troup, K. and Pollard, A. and Aranda, S. and  Schofield, P.",<br/>
 title = "Development of a psychoeducational intervention ",<br/>
 journal = "Journal of Psychosocial Oncology",<br/>
 volume = "27",<br/>
 number = "1",<br/>
 pages = "136-153",<br/>
 year = 2009<br/>
}<br/>

@book{bottoff2008women,<br/>
  author = "Bottoff, J. L. and Oliffe, J. L. and Halpin, M. and Phillips, M. and McLean, G. and Mroz, L.",<br/>
  title = "Women and prostate cancer support groups: {The} gender connect? {Social} {Science} & {Medicine}",<br/>
  publisher = "66",<br/>
  pages = "1217-1227",<br/>
  year = 2008<br/>
}<br/>

@article{bottorff2012gender,<br/>
 author = "Bottorff, J. L. and Oliffe, J. L. and Kelly, M.",<br/>
 title = "The gender (s) in the room",<br/>
 journal = "Qualitative Health Research",<br/>
 volume = "22",<br/>
 number = "4",<br/>
 pages = "435-440",<br/>
 year = 2012<br/>
}

Я хочу захватить строку между двойными кавычками только части @article. Получаю счет @article и диапазон полей @article, чтобы получить значения элементов @article. Использование для цикла am получает значения @article (для значений цикла: диапазон @article для следующего @article и т.д.) Проблема заключается, например, первая строка @article находится в 10-й строке, а вторая - в 18-й строке, am делая цикл между этим диапазоном и получая значение, но между ними @book также существует так, как устранить этот диапазон букв @book в цикле. Потому что он захватывает элементы @book также, поскольку он находится внутри диапазона @article.

PHP-код:

<?php
$file=file("master.bib");
$typeart=array();
$cont=array();

//count of article
$key = '@article';
foreach ($file as $l => $line) {
    if (strpos($line,$key) !== false) {
       $l++;
       $typeart[]= $l;

          }
}//end-count of article

$counttypeart=count($typeart);

for($j=0;$j<$counttypeart;$j++){

    for($i=$typeart[$j];$i<$typeart[$j+1];$i++){
if(strpos($file[$i],'author')){
preg_match('/\"(.*?)\"/',$file[$i],$cont);             
$author= $cont[1];
echo $author;
echo "<br>";    
}   
if(strpos($file[$i],'title')){
preg_match('/\"(.*?)\"/',$file[$i],$cont);             
$title= $cont[1];
echo $title;
echo "<br>";
}
if(strpos($file[$i],'journal')){
preg_match('/\"(.*?)\"/',$file[$i],$cont);             
$journal= $cont[1];
echo $journal;
echo "<br>";
}

if(strpos($file[$i],'volume')){
preg_match('/\"(.*?)\"/',$file[$i],$cont);             
$volume= $cont[1];
echo $volume;
echo "<br>";
}

if(strpos($file[$i],'number')){
preg_match('/\"(.*?)\"/',$file[$i],$cont);             
$number= $cont[1];
echo $number;
echo "<br>";
}

if(strpos($file[$i],'pages')){
preg_match('/\"(.*?)\"/',$file[$i],$cont);             
$pages= $cont[1];
echo $pages;
echo "<br>";
echo "<br>";
}
}
}

?>

Ожидаемый результат (из вышеприведенного примера):

Boonzaier, A. and Schubach, K. and Troup, K. and Pollard, A. and Aranda, S. and Schofield P.
Development of a psychoeducational intervention for men with prostate cancer
Journal of Psychosocial Oncology
27
1
136-153


Bottorff, J. L. and Oliffe, J. L. and Kelly, M.
The gender (s) in the room
Qualitative Health Research
22
4
435-440
Теги:

1 ответ

1
Лучший ответ

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

Есть два альтернативных способа исправить ваш код:

  1. Запишите начальную и конечную строки элемента @article, когда вы первоначально просматриваете все строки в файле. Например:

    // count of article
    $key_start = '@article';
    $key_end = '}<br/>';
    foreach ($file as $l => $line) {
        if (strpos($line,$key_start) !== false) {
            $start = ++$l;
            next;
        }
        if (strpos($line,$key_end) !== false) {
            $typeart[] = array($start, --$l);
            next;
        }
    }
    // end-count of article
    

    Теперь вы должны иметь возможность выполнять итерацию по линиям, принадлежащим элементу @article, просто:

    for($j=0;$j<$counttypeart;$j++){
        list($start, $end) = $typeart[$j];
    
        for ($i=$start; $i<=$end; $i++) {
        …
    
  2. Выйди из своего второго for цикла раньше, как только вы придете к закрытию тега @article. Таким образом, избегая итерации по всем строкам до следующего элемента @article, например:

    for($i=$typeart[$j];$i<$typeart[$j+1];$i++){
        $key_end = '}<br/>';
        break if (strpos($line,$key_end) !== false);
        …
    

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

Альтернативное решение:

  1. читать во всем тексте библиографии сразу
  2. использовать регулярное выражение для захвата содержимого всех элементов @article
  3. используйте другое регулярное выражение для захвата имен параметров и их значений в захваченном содержимом отдельных элементов @article

Ниже приводится краткая реализация того, что я говорю:

<?php

// Use file_get_contents() instead of file() as it is the preferred way
// read the contents of a file into a string. It will also use memory mapping
// techniques if supported by your OS to enhance performance.
$file_content = file_get_contents('master.bib');

// Capture all article container from file content. We use a regular 
// expression on a multi-line string to do that:
preg_match_all(
    '%@article{\w+,<br/>\s+(.*)\s+}(<br/>)?%sUu',
    $file_content,
    $articles,
    PREG_PATTERN_ORDER
);

// Initialise empty results (plural) container which will store results data 
// for all @article elements
$results = array();

// At this point $articles[0] is an array of all captured @article blocks 
// and $articles[1] is an array of all captured first parenthesis within 
// the above regular expression.
foreach ($articles[1] as $article) {

    // Initialise empty result (singular) container which will store results
    // for the current @article element
    $result = array();

    // Now we will take the content of the first paranthesis, split it into
    // individual lines and pick out reqired data from those lines.
    foreach (explode("\n", $article) as $line) {
        $found = preg_match(
            '%\s*(\w+)\s*=\s*"?([^"]+)"?,?<br/>\s*%Uu',
            $line,
            $matches
        );

        // At this point $matches is populated with our desired data, unless
        // $found is 0 (no matches where found) or false (an error occurred)
        if ($found != false and $found > 0) {
            $result[$matches[1]] = trim($matches[2]);
        }
    }

    // Add current @article results to the list of all results, but avoid
    // doing so if current results are empty
    if (!empty($result)) {
        $results[] = $result;
    }
}

// Print results
foreach ($results as $article) {
    print "{$article['author']}\n"
        . "{$article['title']}\n"
        . "{$article['journal']}\n"
        . "{$article['volume']}\n"
        . "{$article['number']}\n"
        . "{$article['pages']}\n"
        . "\n\n";
}
  • 1
    Спасибо за Ваш ответ. С некоторыми изменениями мой код заработал

Ещё вопросы

Сообщество Overcoder
Наверх
Меню