Регулярные выражения — ликбез по регэкспам

Здесь обсуждаются темы, косвенно связанные с Far.
User avatar
Wave
Posts: 1885
Joined: Thu 04 Aug, 2005 18:47
Has thanked: 14 times
Been thanked: 26 times

Регулярные выражения — ликбез по регэкспам

Post by Wave »

Очень хотелось бы больше примеров по регэкспам в документации, т.к. впервые столкнувшись с серьёзной задачей, разобраться очень трудно. Сколько ни бился, так и не получилось такое вот: имеется много html\xml файлов, в них теги прописаны большими, маленькими буквами и смешаным регистром. У тегов естессно, есть параметры, причём в виде: параметр=значение, параметр="значение", параметр='значение'. Требуется привести теги и их параметры, не имеющие смешаного регистра, к \l, при этом ни в коем случае не менять регистр значений. Более того, все значения нужно взять в кавычки.

Т.е. <A HREF=http://www.some.com/REG.HTML>...</A> нужно перевести в <a href="http://www.some.com/REG.HTML">...</a>
<SomeTag SomeParam=SomeValue /> перевести <SomeTag SomeParam="SomeValue" />,
а, допустим <meta http-equiv="Content-Type" content=text/html; charset=windows-1251> в <meta http-equiv="Content-Type" content="text/html;" charset="windows-1251">

Задача номер следующая: теги, не имеющие закрывающую пару, и не закрывающиеся сами - закрыть. Т.е. те же <meta http-equiv="Content-Type" content="text/html;" charset="windows-1251"> перевести в <meta http-equiv="Content-Type" content="text/html;" charset="windows-1251" />
<img src="..."> в <img src="..." />

Я так понимаю, что задача выполнимая. Но как это сделать? По существующей документации разобраться очень трудно.

<img src="..."> - это если (<.*?\s)(.*?(?<![\/|\/\s])>) и как-то обозначить, что дальше по тексту не встречается $1.*?(?<=[\/|\/\s])> - как-то так...
То тогда менять на $1...[внутренности тега]... /> Во всяком случае такая строка поиска находит теги, не закрывающие сами себя... И в то же время такие вот вещи "<b> some </b>some<b>" (оказывается выделенным всё, что в кавычках). Но как дальше? И как избежать вот этих ошибок. Нужно как-то обозначить, что внутри $1 не должно быть ">" и вообще та закрывающая скобка, которая явно нарисована, должна быть первой закрывающей.

Да, ещё, нужно учесть, что закрывающий тег может быть и не в той же самой строке. А в сложных случаях - вложенность тегов...

И ещё, можно ли как-то указать, что группа должна быть больше, меньше, равно, не больше, не меньше, чем столько-то символов? Не считая, конечно, явного составления из "ровно один любой символ". Могу я для строки AZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX указав A.*X, указать ещё и длину не больше 15 символов? Хотя здесь ещё просто, а вот для предыдущих упражнений с тегами задавать длину не более 75 символов со всеми параметрами?

Как можно задать строку-исключение? "XXX" не должна входить в "A.*?Z".

Думаю, если подробный разбор этого дела сделать (с пояснениями), то практически с любой степенью сложности регэкспов можно будет справиться. Или есть и более сложные примеры?

(<(?!\/).+?\s(?<!>))(.*?(?<![\/|\/\s])>) находит "<b> some </b>", но не "<b> some </b>some<b>" (без кавычек).
А ещё "<pre><font size=4>".
(<(?!\/).+?[\s>](?<!>))(.*?(?<![\/|\/\s])>) и того хуже.
Пользуюсь ФАРом больше 20 лет © собирательный.
al666
Posts: 239
Joined: Mon 04 Jul, 2005 08:55
Been thanked: 1 time

Post by al666 »

Рекомендую не пытаться объять необъятное (или впихнуть невпихуемое - кому как больше нравится :).
Все перечисленное надо разбить на отдельные маленькие задачи.

Например:
1) исправление регистра в открывающих тегах
искать: <[A-Z ]+?=
заменить: \L$0

2) исправление регистра в закрывающих тегах
искать: <\/[A-Z]+?>
заменить: \L$0

3) замена одинарных кавычек на двойные:
искать: ='(\w+)'
заменить: ="$1"

и так далее...

P.S. Насчет ограничения длины для выражения <regexp> - попробуй (?=<regexp>)<.{1,75}>
User avatar
Centaur
Posts: 1083
Joined: Tue 05 Apr, 2005 20:09
Location: Novosibirsk, Russia
Been thanked: 2 times

Post by Centaur »

Регулярные выражения — самый слабый из способов задания языков. Не надо хотеть решать ими все задачи обработки текста.

Вышеописанная задача больше похожа на приведение достандартного HTML к формату XHTML или XML. Её решает, например, программа HTML Tidy.
User avatar
Wave
Posts: 1885
Joined: Thu 04 Aug, 2005 18:47
Has thanked: 14 times
Been thanked: 26 times

Post by Wave »

al666 - спасибо. Попробую от этого поплясать.
Centaur - посмотрю и прогу. Мне действительно часто приходится приводить
HTML к XHTML\XML. Но, во-первых: не только. Во-вторых: если это самый слабый
способ задания языков - то что сильней (из универсальных средств)?

К регэкспам я пришёл после программулины HTMLchanger (http://sura.ru/emanovs/)
- мощнейшая вещь для пакетной обработки файлов с довольно простым и слабоватым
синтаксисом. Однако с её помощью я, к примеру, поубирал банеры из сотен
мегабайт документации. Там можно задавать сразу много шаблонов\схем сразу, чего
нельзя в s_and_r\REsearch. А ещё там есть не только подтверждение, но и
возможность редактировать на лету результат замены - в диалоге подтверждения
это предусмотрено. Ну и ещё вкусности.

HTMLchanger'а перестало хватать для моих задач, зато открыл для себя регэкспы.
Которые посложней будут. Вот и хочу разобраться с ними. А проще всего это
сделать на примерах, которые хотелось бы иметь сразу в стандартной поставке.
Готов даже поделиться своим опытом.

Здесь ещё одна задача: многие плугины основаны как раз на сабже. К примеру
TrueTemplate. Не умея читать этот синтаксис хотя бы на уровне любимого языка
программирования, разобраться с плугином сложно - проще снести и забыть.
Пользуюсь ФАРом больше 20 лет © собирательный.
User avatar
Px
Posts: 826
Joined: Fri 08 Sep, 2006 15:52
Location: Вишнёвый (под Киевом)
Contact:

Re: Far 2.0 - regexp

Post by Px »

Небольшой вопрос: хочу убрать в файле \N между словами, но оставить там, где он есть после точки или другого знака препинания
Пример:
всегда\Nмогу
сегодня\Nне
regexp для поиска сделал такой

Code: Select all

(\l)\\N(\l)
а вот что подставить в диалог замены, чтобы \N заменилось на пробел, а соседние символы остались неизменными? :oops:
Shmuel
Posts: 6815
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 41 times
Been thanked: 526 times

Re: Far 2.0 - regexp

Post by Shmuel »

$1 $2
User avatar
Px
Posts: 826
Joined: Fri 08 Sep, 2006 15:52
Location: Вишнёвый (под Киевом)
Contact:

Re: Far 2.0 - regexp

Post by Px »

Спасибо!
User avatar
WARP ItSelf
Самый умный
Posts: 1011
Joined: Tue 15 Mar, 2005 23:19
Contact:

Помогите с регулярным выражением.

Post by WARP ItSelf »

Задача такая, есть строка с версией (сами знаете чего :P ). Строка имеет довольно произвольный вид, известно о ней только то, что она содержит числа, точки и буквы. Подходящие строки:

1.0 alpha 1
2.0.0rc2
1.0.0a
1.0.0.5

Задача - попилить эту строку с помощью регулярных выражений так, чтобы на выходе получить 4 числа (если их там есть 4, можно меньше) и все огрызки строк. Точки не нужны.
Никто не знал, а я...
User avatar
HaRT
Moderator
Posts: 10806
Joined: Tue 30 Aug, 2005 17:21
Has thanked: 220 times
Been thanked: 357 times

Re: Помогите с регулярным выражением.

Post by HaRT »

В предположении, что строка начинается с цифры, правильно ли я понял, что строка имеет такой вид:
ЦЦ1 ТП БП1 ТП ЦЦ2 ТП БП2 ТП ЦЦ3 ТП БП3 ТП ЦЦ4 ТП БП4,
где
ЦЦ# — цифры
БП# — буквы и подчерки
ТП — точки и пробелы
Фар есть инструмент, а не нянька. © 2009 DrKnS
Shmuel
Posts: 6815
Joined: Thu 23 Mar, 2006 21:36
Location: Israel
Has thanked: 41 times
Been thanked: 526 times

Re: Помогите с регулярным выражением.

Post by Shmuel »

Code: Select all

(\d+)[\. ]?(\D*)(\d*)[\. ]?(\D*)(\d*)[\. ]?(\D*)(\d*)[\. ]?(\D*)
$1, $3, $5, $7 будут содержать числа (или пустые строки, если числа нет)
$2, $4, $6, $8 - аналогично для "огрызков строк", одиночные точки и пробелы - пропускаются.
darkmist
Posts: 124
Joined: Wed 08 Aug, 2007 19:44

Re: Помогите с регулярным выражением.

Post by darkmist »

cat <<EOL | perl -MData::Dumper -ne"my @a = grep { not /^(\s+|\.|)$/ } split /(\s+|\.|\d+|\a+)/; print Dumper( \@a )"
1.0 alpha 1
2.0.0rc2
1.0.0a
1.0.0.5
EOL
dmk
Posts: 32
Joined: Tue 26 Feb, 2008 10:01

Re: Помогите с регулярным выражением.

Post by dmk »

на питоне:
ss = ("1.0 alpha 1",
"2.0.0rc2",
"1.0.0a",
"1.0.0.5"
)

import re

for s in ss:
m = re.match(r'(\d+)(\.(\d+))?(\.(\d+))?(\.(\d+))?(.*)', s)
if m:
print m.group(1, 3, 5, 7, 8)
-----------------------
('1', '0', None, None, ' alpha 1')
('2', '0', '0', None, 'rc2')
('1', '0', '0', None, 'a')
('1', '0', '0', '5', '')
User avatar
WARP ItSelf
Самый умный
Posts: 1011
Joined: Tue 15 Mar, 2005 23:19
Contact:

Re: Помогите с регулярным выражением.

Post by WARP ItSelf »

Shmuel

Взлетело, похоже. Спасибо.

Всем остальным тоже спасибо, временно отбой, пока работает.
Никто не знал, а я...
AGu
Posts: 111
Joined: Wed 16 Mar, 2005 13:17
Location: Novosibirsk
Contact:

Re: Помогите с регулярным выражением.

Post by AGu »

На JScript

Code: Select all

var TestStrings = [
  '1.0 alpha 1',
  ' 2.0.0rc2 ',
  '1.0.0a',
  '1.0 RC 2 10 beta 5'
];

var NumbersRE = /\d+/g;
var OthersRE  = /[^\d\.\s][^\d\.]*?(?=[\d\.\s]|$)/g;

function show(a){
  if(a==null || a.length==0) return ' not found';
  var result = '';
  for(var n=0; n<a.length; ++n) result += ' "'+a[n]+'"';
  return result;
}

for(var i=0; i<TestStrings.length; ++i){
  var s = TestStrings[i];
  WScript.echo(
    '"'+s+'"\r\n'+
    '\r\n'+
    '  Numbers:'+show(s.match(NumbersRE))+'\r\n'+
    '  Others:' +show(s.match(OthersRE)) +'\r\n');
}
Max Rusov
Posts: 3651
Joined: Wed 23 Nov, 2005 11:11
Location: Москва-Питер
Has thanked: 2 times
Been thanked: 19 times

Re: Помогите с регулярным выражением.

Post by Max Rusov »

WARP ItSelf wrote:Взлетело, похоже.
Ну когда же?...
Post Reply

Return to “Операционные системы, командные оболочки и прочее”