-
Notifications
You must be signed in to change notification settings - Fork 10
/
ch04s17.html
111 lines (111 loc) · 13.8 KB
/
ch04s17.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Примеры из практики.</title><link rel="stylesheet" href="chs/default.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.75.1"><link rel="home" href="index.html" title="Краткий учебник по sed."><link rel="up" href="ch04.html" title="Глава 4. Примеры скриптов."><link rel="prev" href="ch04s16.html" title="Восстановление данных и файловая система."><link rel="next" href="ch04s18.html" title="Интерактивная sed."></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Примеры из практики.</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s16.html">Пред.</a> </td><th width="60%" align="center">Глава 4. Примеры скриптов.</th><td width="20%" align="right"> <a accesskey="n" href="ch04s18.html">След.</a></td></tr></table><hr></div><div class="section" title="Примеры из практики."><div class="titlepage"><div><div><h3 class="title"><a name="id2526898"></a>Примеры из практики.</h3></div></div></div><div class="section" title="Замена некоторых символов в некоторых выбранных подстроках."><div class="titlepage"><div><div><h4 class="title"><a name="id2526903"></a>Замена некоторых символов в некоторых выбранных подстроках.</h4></div></div></div><p>
Часто нужно заменить не все символы в строке, а только некоторые, те, что попадают под заданное регулярное выражение. К примеру, недавно мне потребовалось заменить выражение /%5B/ на скобку <span class="quote">«<span class="quote">[</span>»</span>, но не везде, а лишь НЕ внутри ED2K ссылок. Как это сделать?
</p><p>
Ясно, что простая команда <span class="command"><strong>s</strong></span> тут не применима, следует воспользоваться каким-то другим приёмом, лично я использовал технику маркёров - я попросту стёр все места где замена не требуется, и вместо них вставил туда маркёрные байты. После чего и произвёл замену:<span class="command"><strong>s/%5B/[/g; s/%5D/]/g</strong></span> Как видите - всё просто. Команда удаления тех мест, где замена не нужна тоже тривиальна: <span class="command"><strong>s~\[url=ed2k://[^]]+\]~\r~ig</strong></span> (подразумевается, что мы уже очистили текст от <span class="quote">«<span class="quote">\r</span>»</span>).
</p><p>
Теперь нам нужно поменять маркёры на нужные подстроки. Сделать это не так уж и сложно, проблема лишь в их очерёдности. В силу того, что регулярное выражение /.*МАРКЁР/ захватывает все маркёры до последнего, проще всего как раз с последнего и начать, и заменить их все в цикле, я это сделал так:
</p><pre class="programlisting">:l4
# вставляем последнюю ссылку на своё место в цикле
s~^(.*)\r([^\n]*)\n(.*)(\[url=ed2k://[^]]+\])(.*)$~\1\4\2\n\3\5~i
t l4</pre><p>
Как видите, ничего архисложного - тут у меня два особых символа: <span class="quote">«<span class="quote">\r</span>»</span> я использую в качестве маркёра, а вот <span class="quote">«<span class="quote">\n</span>»</span> используется в качестве разделителя. В выражении для поиска дважды встречается /.*/ - мы ищем именно последнее совпадение (третье вхождение /.*/ я не считаю - это просто хвост, который надо сохранять).
</p><p>
Безусловно, я приведу и весь скрипт целиком:
</p><pre class="programlisting">/%5B|%5D/{
#замена скобок обратно. Заменяются только вне bbcode
\~\[url=ed2k://~{
# у нас есть ed2k ссылки, сохраняем строку
h
# вырезаем ссылки
s~\[url=ed2k://[^]]+\]~\r~ig
# меняем скобки и палки
s/%5B/[/g
s/%5D/]/g
# добавляем старую строку
G
t l4
:l4
# вставляем последнюю ссылку на своё место в цикле
s~^(.*)\r([^\n]*)\n(.*)(\[url=ed2k://[^]]+\])(.*)$~\1\4\2\n\3\5~i
t l4
# отрезаем ненужный хвост
s/\n.*//
b l5
}
s/%5B/[/g
s/%5D/]/g
:l5
}
</pre><p>
</p></div><div class="section" title="Ещё один способ замены некоторых подстрок в выбранных подстроках. При использовании мультистрочного текста."><div class="titlepage"><div><div><h4 class="title"><a name="id2527047"></a>Ещё один способ замены некоторых подстрок в выбранных подстроках. При использовании мультистрочного текста.</h4></div></div></div><p>
Недавно мне попалась похожая с прошлым примером задача: имелась большая строка (1-50Кбайт), которая представляет собой некий текст. Этот текст вообще говоря являлся HTML текстом, но с некоторым исключением: в обычном HTML все последовательности пробельных символов (<span class="quote">«<span class="quote"> </span>»</span>, <span class="quote">«<span class="quote">\t</span>»</span>, <span class="quote">«<span class="quote">\r</span>»</span>, и <span class="quote">«<span class="quote">\n</span>»</span>) эквивалентны одному пробелу, но есть и исключение:
</p><p>
Некоторый текст можно заключить в теги <pre></pre>, и тогда этот текст должен быть выведен "как есть". Моя задача была преобразовать этот HTML в текст, причём ограничителем "кода" выступало очень сложное регулярное выражение (скорее очень громоздкое). И кроме того, я не мог использовать символ <span class="quote">«<span class="quote">\n</span>»</span> в качестве разделителя.
</p><p>
Для начала я стёр 2 символа, которые я решил использовать в качестве маркёров:
</p><pre class="programlisting">
s/@/<а>/g
s/~/<я>/g
</pre><p>
(обратите внимание: буква <span class="quote">«<span class="quote">а</span>»</span> тут русская!)
</p><p>
Теперь я имею 2 маркёрных символа, чего мне вполне хватит (именно эти символы были выбраны потому, что они не являются метасимволами regex'пов, и их не надо экранировать). Теперь я могу заменить начальные и конечные части выражения на маркёры:
</p><pre class="programlisting">
s~BEGIN~@<код>~g
s%END%</код>~%g
</pre><p>
</p><div class="note" title="Замечание" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Замечание</h3>
Словом BEGIN обозначено начало особого участка, словом END - его конец, и также вводятся фиктивные теги для ограничения границ участка, они впоследствии будут заменены.
</div><p>
</p><p>
Получается вот что:
</p><pre class="screen">
текст1@код1~текст2@код2~текст3
</pre><p>
Теперь, когда участки огорожены, я могу сделать копию строки, и отредактировать её участки по отдельности. Пользуясь тем, что в каждой из двух копий я могу попросту стереть ненужные участки:
</p><pre class="programlisting">
h
s/@[^~]*~/@/g
# обработка обычного текста
x
s/^/~/
s/$/@/
s/~[^@]*@/~/g
# обработка <код>
x
</pre><p>
Тут я в обычном тексте меняю куски "кода" на @, а в "коде" меняю обычный текст на ~. Кроме того, в "коде" я ещё и добавляю в начале и в конце строки (точнее всего текста, я уже говорил, он у меня целиком в буфере) символ ~.
</p><p>
Теперь осталось собрать эти два текста воедино. На самом деле это не сложно:
</p><pre class="screen">
текст1@текст2@текст3
~код1~код2~
</pre><p>
Как и в прошлом примере, объёденим строчки, но в данном примере нам ещё нужно удалить лишний символ перевода строки (его втоматически добавляет команда <span class="command"><strong>G</strong></span>).
</p><pre class="programlisting">
G
s/\n~/~/
</pre><p>
(тут используется тот факт, что в строке с "текстом" заведомо нет символов ~, а команда <span class="command"><strong>s///</strong></span> меняет лишь первое совпадение.
получаем следующее:
</p><pre class="screen">
текст1@текст2@текст3~код1~код2~
</pre><p>
Осталось заменить <span class="quote">«<span class="quote">@</span>»</span> на выделенный и обработанный "код". Как и в прошлом примере, меняем по одному фрагменту, начиная с последнего. Фрагмент <span class="quote">«<span class="quote">~код</span>»</span> переносится вместо <span class="quote">«<span class="quote">@</span>»</span>.
</p><pre class="programlisting">
t l8
:l8
s/^(.*)@([^~]*)(.*)~([^~]*)~$/\1\4\2\3~/
t l8
s/~$//
T error
/[~@]/ b error
s/<а>/@/g
s/<я>/~/g
</pre><p>
После замены остаётся символ ~ в конце строки, который и удаляется. На всякий случай проверяется наличие оставшихся маркёров (хотя их вроде быть не может). Ну и после замены спец-тегов скрипт завершается.
</p></div><div class="blockquote"><blockquote class="blockquote"><p>
Вы можете обсудить этот документ на <a class="ulink" href="http://emulek.tk/forum/viewtopic.php?f=19&t=5026" target="_top">форуме</a>. Текст предоставляется по лицензии <a class="ulink" href="http://www.gnu.org/licenses/fdl.html" target="_top">GNU Free Documentation License</a> (<a class="ulink" href="http://forum.lorcode.org/viewtopic.php?f=15&t=30" target="_top">Перевод лицензии GFDL</a>).
</p><p>
Вы можете пожертвовать небольшую сумму яндекс-денег на счёт <span class="command"><strong>41001666004238</strong></span> для оплаты хостинга, интернета, и прочего. Это конечно добровольно, однако это намного улучшит данный документ (у меня будет больше времени для его улучшения). На самом деле, проект часто находится на грани закрытия, ибо никаких денег никогда не приносил, и приносить не будет. Вы можете мне помочь. Спасибо.
</p></blockquote></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch04s16.html">Пред.</a> </td><td width="20%" align="center"><a accesskey="u" href="ch04.html">Уровень выше</a></td><td width="40%" align="right"> <a accesskey="n" href="ch04s18.html">След.</a></td></tr><tr><td width="40%" align="left" valign="top">Восстановление данных и файловая система. </td><td width="20%" align="center"><a accesskey="h" href="index.html">Начало</a></td><td width="40%" align="right" valign="top"> Интерактивная sed.</td></tr></table></div></body></html>