2011-08-03 5 views
0

Хорошо, регулярные ряды ниндзя. Я пытаюсь разработать шаблон для добавления гиперссылок в концевые сноски в файле eHPML ePub ebook. Проблема в том, что нумерация перезапускается в каждой главе, поэтому мне нужно добавить уникальный идентификатор к имени привязки, чтобы связать его с хэш-ссылкой.Можно ли использовать регулярное выражение для копирования заголовка в каждую запись до следующего заголовка? (Гиперссылки концевых сносок в электронной книге)

Учитывая (очень упрощенный) список, как это:

<h2>Introduction</h2> 
<p> 1 Endnote entry number one.</p> 
<p> 2 Endnote entry number two.</p> 
<p> 3 Endnote entry number three.</p> 
<p> 4 Endnote entry number four.</p> 

<h2>Chapter 1: The Beginning</h2> 
<p> 1 Endnote entry number one.</p> 
<p> 2 Endnote entry number two.</p> 
<p> 3 Endnote entry number three.</p> 
<p> 4 Endnote entry number four.</p> 

мне нужно, чтобы превратить его в нечто вроде этого:

<h2>Introduction</h2> 
<a name="endnote-introduction-1"></a><p> 1 Endnote entry number one.</p> 
<a name="endnote-introduction-2"></a><p> 2 Endnote entry number two.</p> 
<a name="endnote-introduction-3"></a><p> 3 Endnote entry number three.</p> 
<a name="endnote-introduction-4"></a><p> 4 Endnote entry number four.</p> 

<h2>Chapter 1: The Beginning</h2> 
<a name="endnote-chapter-1-the-beginning-1"></a><p> 1 Endnote entry number one.</p> 
<a name="endnote-chapter-1-the-beginning-2"></a><p> 2 Endnote entry number two.</p> 
<a name="endnote-chapter-1-the-beginning-3"></a><p> 3 Endnote entry number three.</p> 
<a name="endnote-chapter-1-the-beginning-4"></a><p> 4 Endnote entry number four.</p> 

Очевидно, что необходимо будет аналогичный поиск в фактическом текст книги, где каждая сноска будет связана с endnotes.xhtml#endnote-introduction-1 и т. д.

Самое большое препятствие в том, что поиск каждого матча начинается ПОСЛЕ предыдущего поиска, поэтому, если вы не используете рекурсию, вы не можете сопоставить один и тот же бит (в данном случае название) для нескольких записей. Однако мои попытки рекурсии дали лишь бесконечные циклы.

Я использую grep-движок TextWrangler, но если у вас есть решение в другом редакторе (например, vim), это тоже хорошо.

Спасибо!

+1

Анализ HTML с регулярным выражением? Взгляните на это http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags – Penang

ответ

1

Немного AWK может сделать трюк:

Создайте следующий скрипт (я назвал его add_endnote_tags.awk):

/^<h2>/ { 
    i = 0; 
    chapter_name = $0; 
    gsub(/<[^>]+>/, "", chapter_name); 
    chapter_name = tolower(chapter_name); 
    gsub(/[^a-z]+/, "-", chapter_name); 
    print; 
} 

/^<p>/ { 
    i = i + 1; 
    printf("<a name=\"endnote-%s-%d\"></a>%s\n", chapter_name, i, $0); 
} 

$0 !~ /^<h2>/ && $0 !~ /^<p>/ { 
    print; 
} 

, а затем использовать его для разбора файла:

awk -f add_endnote_tags.awk <source_file.xml> dest_file.xml 

Надеюсь, что это поможет. Если вы находитесь на платформе Windows, вам может потребоваться установить awk либо путем установки cygwin, либо пакета awk или загрузки gawk for Windows

+0

Элегантное решение, мне нравится, что вы можете легко выполнить процесс с ним. – Yorb

1

Я думаю, что это трудно выполнить в текстовом редакторе, поскольку для этого требуется двухэтапный процесс. Сначала вам нужно разделить файл на главы, затем вам нужно обработать содержимое каждой главы. Предполагая, что «абзацы концевой сноски» (где вы хотите добавить привязки), определяются как абзацы, имеющие первое слово, равное целочисленному слову, тогда этот PHP-скрипт будет делать то, что вам нужно.

<?php 
$data = file_get_contents('testdata.txt'); 
$output = processBook($data); 
file_put_contents('testdata_out.txt', $output); 
echo $output; 

// Main function to process book adding endnote anchors. 
function processBook($text) { 
    $re_chap = '% 
     # Regex 1: Get Chapter. 
     <h2>([^<>]+)</h2> # $1: Chapter title. 
     (     # $2: Chapter contents. 
      .+?    # Contents are everything up to 
      (?=<h2>|$)  # next chapter or end of file. 
     )     # End $2: Chapter contents. 
     %six'; 
    // Match and process each chapter using callback function. 
    $text = preg_replace_callback($re_chap, '_cb_chap', $text); 
    return $text; 
} 
// Callback function to process each chapter. 
function _cb_chap($matches) { 
    // Build ID from H2 title contents. 
    // Trim leading and trailing ws from title. 
    $baseid = trim($matches[1]); 
    // Strip all non-space, non-alphanums. 
    $baseid = preg_replace('/[^ A-Za-z0-9]/', '', $matches[1]); 
    // Append prefix and convert whitespans to single - dash. 
    $baseid = 'endnote-'. preg_replace('/ +/', '-', $baseid); 
    // Convert to lowercase. 
    $baseid = strtolower($baseid); 
    $text = preg_replace(
       '/(<p>\s*)(\d+)\b/', 
       '<a name="'. $baseid .'-$2"></a>$1$2', 
       $matches[2]); 
    return '<h2>'. $matches[1] .'</h2>'. $text; 

} 
?> 

Этот скрипт правильно выполняет ваши данные примера.

+0

Это то, что я предполагаю, что я закончу, спасибо за подробный ответ! Я немного задержу статус ответа, чтобы узнать, есть ли у кого прямое решение регулярного выражения ... – Yorb