Пример:
@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
Похоже, причина, по которой ваш код захватывает элементы @book
заключается в том, что вы не записываете строку, по которой @article
элемент @article
. Таким образом, когда вы перебираете все строки внутри элемента @article
, вы начинаете с строки, где ваш элемент @article
запускается и заканчивается в строке, где начинается следующий элемент @article
.
Есть два альтернативных способа исправить ваш код:
Запишите начальную и конечную строки элемента @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++) {
…
Выйди из своего второго for
цикла раньше, как только вы придете к закрытию тега @article. Таким образом, избегая итерации по всем строкам до следующего элемента @article
, например:
for($i=$typeart[$j];$i<$typeart[$j+1];$i++){
$key_end = '}<br/>';
break if (strpos($line,$key_end) !== false);
…
Однако ни одно из этих решений не является идеальным, поскольку оба из них приводят к повторяющемуся коду, который трудно поддерживать. Кроме того, он полагается на то, что вы знаете каждый атрибут внутри элемента @article
, чтобы зафиксировать его значение. Если у вас нет веских оснований структурировать ваш подход, я бы выбрал альтернативное решение...
Альтернативное решение:
@article
@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";
}