Помогите с регулярными выражениями (Parsing Wikipedia Markup) в PHP - PullRequest
2 голосов
/ 19 января 2010

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

{{Historical populations|type=USA
| 1698|4937
| 1712|5840
| 1723|7248
| 1737|10664
| 1746|11717
| 1756|13046
| 1771|21863
| 1790|33131
| 1800|60515
| 1810|96373
| 1820|123706
| 1830|202589
| 1840|312710
| 1850|515547
| 1860|813669
| 1870|942292
| 1880|1206299
| 1890|1515301
| 1900|3437202
| 1910|4766883
| 1920|5620048
| 1930|6930446
| 1940|7454995
| 1950|7891957
| 1960|7781984
| 1970|7894862
| 1980|7071639
| 1990|7322564
| 2000|8008288
| 2008*|8363710
|footnote=Beginning 1900, figures are for consolidated city of five boroughs. Sources: 1698–1771,{{cite book|last=Greene and Harrington|first=|title=American Population Before the Federal Census of 1790|publisher=|location=New York|year=1932|isbn=|pages=}}, as cited in: {{cite book|last=Rosenwaike|first=Ira|title=Population History of New York City|publisher=Syracuse University Press|location=Syracuse, N.Y.|year=1972|isbn=0815621558|page=8}} 1790–1990,Gibson, Campbell.[http://www.census.gov/population/www/documentation/twps0027.html Population of the 100 Largest Cities and Other Urban Places in the United States:1790 to 1990], [[United States Census Bureau]], June 1998. Retrieved June 12, 2007. *2008 est[http://factfinder.census.gov/servlet/SAFFPopulation?_event=Search&geo_id=16000US3403940&_geoContext=01000US%7C04000US34%7C16000US3403940&_street=&_county=new+york+city&_cityTown=new+york+city&_state=04000US36&_zip=&_lang=en&_sse=on&ActiveGeoDiv=geoSelect&_useEV=&pctxt=fph&pgsl=160&_submenuId=population_0&ds_name=null&_ci_nbr=null&qr_name=null&reg=null%3Anull&_keyword=&_industry=Census Data for New York city, New York], [[United States Census Bureau]]. Retrieved June 12, 2007.
}}

Следующую часть я также хочу сохранить как простой текст (но не включая части, обернутые"{{" и "}}"

New York is the most populous city in the United States, with an estimated 2008 population of 8,363,710(up from 7.3 million in 1990). This amounts to about 40.0% of New York State's population and a similar percentage of the metropolitan regional population. Over the last decade the city's population has been increasing and demographers estimate New York's population will reach between 9.2 and 9.5 million by 2030.{{cite web |title=New York City Population Projections by Age/Sex and Borough, 2000-2030 |publisher=[[New York City Department of City Planning]] |month=December | year=2006 |url=http://www.nyc.gov/html/dcp/pdf/census/projections_report.pdf |format=PDF |accessdate=2008-09-01}} See also {{cite news |last=Roberts, Sam |title=By 2025, Planners See a Million New Stories in the Crowded City |publisher=New York Times |date=February 19, 2006 |url=http://www.nytimes.com/2006/02/19/nyregion/19population.html?ex=1298005200&en=c586d38abbd16541&ei=5090&partner=rssuserland&emc=rss |accessdate=2008-09-01}}

Спасибо.

Ответы [ 3 ]

2 голосов
/ 19 января 2010

Для очистки вики-страницы используется следующий код, например, такой:

http://en.wikipedia.org/wiki/Tel_Aviv (вы можете увидеть разметку, нажав «изменить эту страницу»

Я получил это возвращено:

"и уступил своей репутации" Средиземноморского мегаполиса, который никогда не спит ". Редакция Haaretz Это финансовая столица страны и крупный центр исполнительского искусства и бизнеса. Городской район Тель-Авива является вторым по величине на Ближнем Востоке. Экономика города и занимает 42-е место среди мировых городов по индексу мировых городов Foreign Policys 2008. Это также самый дорогой город в регионе и 17-й самый дорогой город в мире. Стоимость жизни в Израиле высокая, с Тель-Авивом это самый дорогой город для проживания. По данным Mercer, консалтинговой фирмы, базирующейся в Нью-Йорке, по состоянию на 2008 год Тель-Авив является самым дорогим городом на Ближнем Востоке и 14-м самым дорогим в мире. В этом отношении Сингапур и Париж, и только впереди Сиднея и Дублина. Для сравнения, Нью-Йорк на 22-м месте. "

Что не правильно, ожидаемый результат должен быть:

Тель-Авив-Яффо (иврит: תֵּל־אָבִיב-יָפוֹ; арабский: تل أبيب, Tall ʼAbīb), обычно называемый Тель-Авивом, является вторым по величине городом в Израиле, с населением в 393 900 человек. Город расположен на израильском средиземноморском побережье, его площадь составляет 51,8 кв. Км. Это самый большой и самый густонаселенный город в столичном регионе Гуш-Дан, где с 2008 года проживает 3,15 миллиона человек. Город управляется муниципалитетом Тель-Авив-Яффо во главе с Роном Хулдаем.

Для этого кода PHP:

function clean_wiki_text($text)
  {
    // first get rid of UGC HTML tags
    $text = strip_tags($text);

    // keep convert tag
    $text = preg_replace("/\{\{convert\|([^\|]+)\|([^\|]+)\|[^\}]+\}\}/", "$1$2", $text);

    // remove large blocks (treat as tags)
    $text = preg_replace("/(<![^>]+>)/", '', $text);
    $text = preg_replace('/\{\{\s?/', '<', $text);
    $text = str_replace('}}', ' />', $text);

    $text = str_replace('<! />', '', $text);

    // more wiki formatting
    $text = preg_replace("/'{2,6}/", '', $text);
    $text = preg_replace("/[=\s]+External [lL]inks[\s=]+/", '', $text);
    $text = preg_replace("/[=\s]+See [aA]lso[\s=]+/", '', $text);
    $text = preg_replace("/[=\s]+References[\s=]+/", '', $text);
    $text = preg_replace("/[=\s]+Notes[\s=]+/", '', $text);
    $text = preg_replace('/\{\{([^\}]+)\}\}/', '', $text);

    // drop page link text
    $text = preg_replace('/\[\[([^:\|\]]+)\|([^:\]]+)\]\]/', "$2", $text);
    // or keep it with preg_replace('/\[\[([^:\|\]]+)\|([^:\]]+)\]\]/', "$1 ($2)", $text);

    $text = preg_replace('/\(\[[^\]]+\]\)/', '', $text);
    $text = preg_replace('/\[\[([^:\]]+)\]\]/', "$1", $text);
    $text = preg_replace('/\*?\s?\[\[([^\]]+)\]\]/', '', $text);
    $text = preg_replace('/\*\s?\[([^\s]+)\s([^\]]+)\]/', "$2", $text);
    $text = preg_replace('/\n(\*+\s?)/', '', $text);
    $text = preg_replace('/\n{3,}/', "\n\n", $text);
    $text = preg_replace('/<ref[^>]?>[^>]+>/', '', $text);
    $text = preg_replace('/<cite[^>]?>[^>]+>/', '', $text);

    $text = preg_replace('/={2,}/', '', $text);
    $text = preg_replace('/{?class="[^"]+"/', "", $text);
    $text = preg_replace('/!?\s?width="[^"]+"/', "", $text);
    $text = preg_replace('/!?\s?height="[^"]+"/', "", $text);
    $text = preg_replace('/!?\s?style="[^"]+"/', "", $text);
    $text = preg_replace('/!?\s?rowspan="[^"]+"/', "", $text);
    $text = preg_replace('/!?\s?bgcolor="[^"]+"/', "", $text);

    $text = trim($text);

    $text = preg_replace('/\n\n/', "<br />\n<br />\n", $text);
    $text = preg_replace('/\r\n\r\n/', "<br />\r\n<br />\r\n", $text);
/*
    $config = array(
      'show-body-only' => true,
      'clean'          => false, 
      'wrap'           => 0, 
      'show-warnings'  => 0,
      'show-errors'    => 0,
      'enclose-block-text'   => false,
      'vertical-space' => true,
      'output-html'    => true
    );

    // Tidy
    $tidy = new tidy;
    $tidy->parseString($text, $config, 'utf8');
    $tidy->cleanRepair();

    $text = $tidy->value;
*/
    $extras = array(
  //  "/\((.*?)\)/is" => "",
      "/\[(.*?)\]/is" => ""
    );
    $text = preg_replace(array_keys($extras), array_values($extras), $text);

    $text = str_replace(" ,", ',', $text);
    $text = str_replace(", ", ',', $text);
    $text = str_replace(",", ', ', $text);
    $text = str_replace("(, ", '(', $text);
    $text = str_replace(";,", ',', $text);

    // lets keep it plain plain plain
    $text = strip_tags($text);
//    $text = preg_replace('/\s\s+/', ' ', $text);

    $text = str_replace("|-", '', $text);
    $text = str_replace("|}", '', $text);
    $text = str_replace("|", '', $text);
    $text = str_replace('()', '', $text);
    $text = str_replace('&nbsp;', ' ', $text);

    $text = trim($text);

    $text_arr = preg_split('/[\r\n]+/', $text, -1, PREG_SPLIT_NO_EMPTY);
    $result = "";
    foreach ($text_arr as $paragraph) {
      if ( mb_strlen(trim($paragraph)) > 30 ) {
      $result[] = $paragraph;
      }
    }
    return $result;
  }
1 голос
/ 27 января 2010

Просто угадайте здесь, но не будет ли проще и безопаснее использовать библиотеку разметки Википедии (в комплекте с Mediawiki), превратить ее в HTML, а затем проанализировать ее, используя любую библиотеку XML, с которой вам удобно?

Документацию по API можно найти по адресу http://svn.wikimedia.org/doc/ (в модуле Parser), и она не выглядит очень сложной. По сути, все, что вам нужно сделать, это что-то вроде следующего:

<?php

require_once '/path/to/mediawiki/Parser.php';
// also include whatver classes Parser depends on or use Mediawiki's autoload
// mechanism if it has any

// retrieve the content of your page in $content

$parser = new Parser();
$html   = $parser->parse($content);

$simplexml = simplexml_load_string($html);

Теперь у вас есть очень удобный объект SimpleXML для игры. Конечно, это работает только в том случае, если анализатор Mediawiki создает допустимый XML (что, я уверен, он делает).

Кроме того, если бы в Mediawiki был какой-то механизм автозагрузки, было бы легко найти его, найдя __autoload или spl_autoload_register в базе кода Mediawiki.

Надеюсь, это поможет!

0 голосов
/ 19 января 2010

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

{{.+?}}\n

Это работает только в том случае, если после удаляемой детали есть символ новой строки и вы указываете DOTALL и MULTILINE. Сопоставьте все пары двойных фигурных скобок и все, что внутри, с:

{{[^}]+}}

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

...