Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > интерполяция метасимволов


Автор: 1one 26.6.2007, 15:41
Как с помощью регекспа заменить метасимволы перевода строки (\n) на _сам_ символ перевода строки (0xA), учитывая перекрывающиеся слеши ('\\\\n' будет '\\n')?
Т.е. сделать вручную то, что автоматически делается, например, строкой print "one\ntwo\\\\nthree" (вывод в STDOUT в двойных кавычках) (на выходе будет one
two\\nthree)

на примере кода:

#!/usr/local/bin/perl -w

use strict;

print "------ Original:\n";
print "one\ntwo\\\\nthree";

my $str = 'one\ntwo\\\\nthree';
$str =~ s/(?<!\\)\n/\n/;

print "------ Code:\n";
print $str;

Автор: Nab 26.6.2007, 15:57
Так что именно должно получиться то?

Приведите пример выходной строки.

Автор: nitr 26.6.2007, 16:01
вариантов много - один из них:
Код

$str =~ s/[\\]+n/\n/g;

Автор: 1one 26.6.2007, 16:02
Цитата(Nab @ 26.6.2007,  15:57)
Приведите пример выходной строки.

например,
есть строка 'one\ntwo\\nthree\\\nfour\\\\nfive'

на выходе будет:

one
two\nthree\
four\\nfive

т.е. то же самое, если бы вы вывели print "one\ntwo\\nthree\\\nfour\\\\nfive";

Автор: nitr 26.6.2007, 16:03
а если бэкслеш как символ, то так:
Код

$str =~ s/\\n/\n/g;


З.Ы.: ответьте на вопрос Nab - для уточнения

Добавлено через 1 минуту и 14 секунд
вооо - теперь понято стало =)

Автор: Nab 26.6.2007, 16:05
Цитата(nitr @ 26.6.2007,  16:01)
вариантов много - один из них:
Код

$str =~ s/[\\]+n/\n/g;

nitr, ты чего?
самый простой способ, это:
Код

$str = "$str";
print $str;


 smile 

Автор: nitr 26.6.2007, 16:08
Nab, уверен? smile)

Автор: 1one 26.6.2007, 16:11
Nitr, Nab - не верно.

"$str" \n, которые уже были в $str не заменит на символы перевода строки

$str =~ s/[\\]+n/\n/g; - сотрет все предыдущие слеши (а надо их оставить)

повторюсь:
нужно сделать в точности так, как происходит вывод в STDOUT в двойных кавычках.

но нужно вывести не

print "one\ntwo\\nthree\\\nfour\\\\nfive";

, а

$str = '"one\ntwo\\nthree\\\nfour\\\\nfive"';
#здесь махинации по преобразованию двойных слешей в одинарные, и \n на 0xA (код симв. перевода строки)
print "$str";

Автор: Nab 26.6.2007, 16:37
Цитата(nitr @  26.6.2007,  16:08 Найти цитируемый пост)
Nab, уверен? smile)

неееее, стыдно... :(
потому проверил, и могу сказать что задача не решаема в принципе smile
потому как интерпретация обратного слеша происходит и в одиночных кавычках...

то есть 
Код

$f = "\\n";
$g = '\\n';

print $f, $g;


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

$str = 'one\ntwo\\nthree`, что она будет иметь вид
Код

one\ntwo\nthree

 дельнейшая обработка безсмысленна, потому как утеряна важная информация, и при интерполяции каким либо способом и первая \n и вторая дадут одинаковое вхождение... Здесь нужна предварительная обработка входных данных, тех которые ниразу не прошли интерпретацию процессором перла...

Автор: 1one 26.6.2007, 16:52
2 Nab:

> Здесь нужна предварительная обработка входных данных, тех которые ниразу не прошли интерпретацию процессором перла...

Данные препроцессором перла не проверяются изначально.

Я выразился "так, как при выводе метасимволов в STDOUT в двойных кавычках" всего-лишь для того, чтобы было понятнее.

перефразирую мою задачку так:

Метасимволами являются '\' и '\n'.
В свою эчередь, их можно экранировать (чтобы они не обрабатывались как спец. символы), поставив перед ними еще один слеш.
Как сделать так, чтобы двойные слеши менялись на одинарные, а \n - на символ перевода строки. Причем замены эти, я так понял, должны идти только строго последовательно, тогда и получится "так, как в выводе в двойн. каычках в STDOUT"

Т.е.
есть у нас \\\\\\n
получим \\\n (двойные слеши заменились одинарными, а для n, в свою очередь, не осталось слеша впереди (т.к. поиск на предмет замен идет попарно по 2 символа), поэтому преобразование в символ перевода строки произведено не было).

-----
Вот и не соображу, как это регекспом выразить...

Автор: Nab 26.6.2007, 17:23
а зачем?

Проще эту работу поручить перлу...
Код

eval "\$str = \"$str\"";



Автор: dimes 26.6.2007, 19:09
Nab
Главное что бы в тексте не встречалась спецуха типа '$' smile

По-моему первый вариант предложенный nitr, "$str =~ s/[\\]+n/\n/g;"
вполне жизнеспособный и быстрый. Или я что то не понимаю?

Автор: Nab 26.6.2007, 20:02
Цитата(dimes @  26.6.2007,  19:09 Найти цитируемый пост)
Главное что бы в тексте не встречалась спецуха типа '$' smile

ну эт уже проблемы другого плана smile

Цитата(dimes @  26.6.2007,  19:09 Найти цитируемый пост)
По-моему первый вариант предложенный nitr, "$str =~ s/[\\]+n/\n/g;"

не совсем, где сказано что в конце по любому 'n' ? и потом ему нужно пару '\\' превратить в одну, а не убить их всех одним махом smile

Я так понял требуеться для общего случая, когда и такое может случиться: 'aaa\\\n\\\\bb'...

Автор: 1one 27.6.2007, 08:14
Цитата(Nab @ 26.6.2007,  20:02)
не совсем, где сказано что в конце по любому 'n' ? и потом ему нужно пару '\\' превратить в одну, а не убить их всех одним махом smile

Я так понял требуеться для общего случая, когда и такое может случиться: 'aaa\\\n\\\\bb'...

вот-вот...

эхх..

Автор: 1one 27.6.2007, 08:44
Цитата(Nab @ 26.6.2007,  17:23)
а зачем?

Проще эту работу поручить перлу...
Код

eval "\$str = \"$str\"";

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

Автор: fantome 27.6.2007, 08:48
1one
Цитата

т.е. то же самое, если бы вы вывели print "one\ntwo\\nthree\\\nfour\\\\nfive";


А если в отладчике ввалиться в функцию print и посмотреть, как она обработает эту строку?
тоисть взять кусок из самой функции...  smile 

Автор: 1one 27.6.2007, 08:58
Цитата(fantome @ 27.6.2007,  08:48)
1one
Цитата

т.е. то же самое, если бы вы вывели print "one\ntwo\\nthree\\\nfour\\\\nfive";


А если в отладчике ввалиться в функцию print и посмотреть, как она обработает эту строку?
тоисть взять кусок из самой функции...  smile

Разве перловая функция написана на самом перле?
Не думаю, что будет удачным преобразование с низкого уровня на уровень перла.

Автор: Nab 27.6.2007, 09:37
Цитата(1one @  27.6.2007,  08:44 Найти цитируемый пост)
Это был бы действительно вариант, если бы не интерпретация и других спецсимволов в том числе - а то, да, может по ошибке и еще какое-нибудь значение левой переменной залезть в результат.

Ээээ нет, не нужно тут ставить новые задачи... Вы или сформулируйте вопрос однозначно или не морочьте голову, а то от первоначального вопроса мы уже ой как далеко ушли... 

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

Автор: 1one 27.6.2007, 10:07
Цитата(Nab @ 27.6.2007,  09:37)
Пример пожалуйста того, что может быть во входной строке, и то что должно в итоге получиться в выходной...

да вопрос то все тот же, просто под разными углами формулирую.

примеры:
------------
1)
на входе:
ma\npa
на выходе:
ma
pa
------------
2)
на входе:
ma\\npa
на выходе:
ma\npa
------------
3)
на входе:
ma\\\npa
на выходе:
ma\
pa
------------
4)
на входе:
ma\\\\npa
на выходе:
ma\\npa
------------

Автор: nitr 27.6.2007, 10:21
Задача решаема не в одну строку, тут и "конечные автоматы" можно и многое другое - регеспы вам не в помощь! Можете сами посмотреть, вывод строки:
Код

print 'one\ntwo\\nthree';

вывод одинаковый, а слешей больше ;)
т.е.
Цитата

one\ntwo\nthree

так что пересмотрите задачу. Лучше, как советовал Nab - получить данные, которые можно обработать.

Автор: 1one 27.6.2007, 10:32
На мой взгляд, решение существует именно в одну строку (на крайний случай - пара-тройка).

Всего то и нужно:
идти _последовательно_ по строке (наверняка в регекспе будет фигурировать метасимвол \G) и заменять {\\ на \} и {\n на 0xA}.

Причем операция замены {\\ на \} по приоритету выше, чем {\n на 0xA}. Вот и все. это и надо уместить в регексп(ы).

Автор: nitr 27.6.2007, 11:12
1one, вы прочли предыдущее предложение. Perl понимает '\n' так же как и '\\n'
Код

print 'ok' if '\n' eq '\\n';

smile так что... совет - прислушаться к совету.

Автор: Nab 27.6.2007, 12:08
1one, вы издеваетесь? Я привел решение, Вы начинаете говорить о левых переменных которые могут попасть в строку, и тут же приводите примеры входных строк без таких нюансов...

Вы бы для себя определились что хотите, а потом начали задавать вопросы....

И ответьче ЧЕМ КОНКРЕТНО НЕ УСТРАИВАЕТ МОЙ ВАРИАНТ?

Все ваши примеры он по определению решает на УРА!

Автор: 1one 27.6.2007, 12:38
Цитата(Nab @ 27.6.2007,  12:08)
1one, вы издеваетесь? Я привел решение, Вы начинаете говорить о левых переменных которые могут попасть в строку, и тут же приводите примеры входных строк без таких нюансов...

Вы бы для себя определились что хотите, а потом начали задавать вопросы....

И ответьче ЧЕМ КОНКРЕТНО НЕ УСТРАИВАЕТ МОЙ ВАРИАНТ?

Все ваши примеры он по определению решает на УРА!

Nab, ты предложил решение
eval "\$str = \"$str\"";

Оно подходит, да. Если бы не одно НО:
строка $str вводится пользователем, который может (случайно) написать во введенной строке как имена служебных переменных (типа $_ $% $@ $! и пр.), так и имя переменной (например, $str), которая существует в коде, в котором выполняется eval'ом эта самая строка. Соответственно, при выполнении eval туда подставится значение указанной переменной.
Экранирование $ на \$ перед исполнением eval у меня проблемы не решило:

Код

# EVAL variant
my $bug = "ZLOI BUG!";
my $str = 'ma\\\\\npa $%$_$! $bug';
$str =~ s/\$/\\\$/; # попробуем защитить от подстановки значения
eval "\$str = \"$str\"";

print "----------\n";
print STDERR $str;
print "\n----------\n";

Автор: JAPH 27.6.2007, 12:43
Проверьте 
Код
s/(\\[\\n])/qq{qq{$1}}/gee


Добавлено через 9 минут
nitr
Код

print "ok" if "\n" eq "\\n";


Конечные автоматы.. А регекспы в перле как реализованы? По-моему, как раз НКА smile

Автор: 1one 27.6.2007, 12:57
Цитата(JAPH @ 27.6.2007,  12:43)
Проверьте 
Код
s/(\\[\\n])/qq{qq{$1}}/gee

JAPH, черт возьми, работает!!! =)
Спасибо.

Теперь вот разберусь че куда в етом регекспе. Почему модификатор e 2 раза и двойные qq...

Автор: nitr 27.6.2007, 13:35
ууууууууууууу

1one, вы сами себе противоречите!!!
Код

#!perl
use strict;
use warnings;

print "------ Original:\n";
print "one\ntwo\\nthree\\\nfour\\\\nfive";

my $str = 'one\ntwo\\nthree\\\nfour\\\\nfive';
$str =~ s/(\\[\\n])/qq{qq{$1}}/gee;

print "\n------ Code:\n";
print $str;

вывод:
Цитата

------ Original:
one
two\nthree\
four\\nfive
------ Code:
one
two
three\nfour\nfive

И все выши попытки - это подгон к результату. Если прочесть тему сначала, будет ясно почему...

Добавлено через 3 минуты и 7 секунд
JAPH, и вы внимательно прочтите...
Код

print "ok" if "\n" eq "\\n";
print "ok" if '\n' eq '\\n';

РАЗНЫЕ ВЕЩИ! Я это специально привел как пример ;)

гляньте на первые 3 поста, там 1one, как бы уточняет суть вопроса и приводит пример, достаточно точный.

Добавлено через 4 минуты и 24 секунды
точнее даже на этом ярче видно:
Код

print "ok1" if "\n" eq "\\n";
print "ok2" if '\n' eq '\\n';

Автор: 1one 27.6.2007, 13:49
Цитата(1one @ 26.6.2007,  16:02)
Цитата(Nab @ 26.6.2007,  15:57)
Приведите пример выходной строки.

например,
есть строка 'one\ntwo\\nthree\\\nfour\\\\nfive'

на выходе будет:

one
two\nthree\
four\\nfive

т.е. то же самое, если бы вы вывели print "one\ntwo\\nthree\\\nfour\\\\nfive";

Задачка решена.
Nitr, Nab, вам тоже спасибо за обсуждение.

ps: Nitr, я выразился неточно значит. В цитате "то же самое" надо, видимо, заменить на "почти то же самое". Я не знал, что perl пакостит с ('\n' eq '\\n').

В общем, всем thanks, specially thanks for JAPH.

Автор: JAPH 27.6.2007, 14:06
smile гы...
Меня несколько смущает следующее:
Код
my $s = 'asd\\\\nasd\\nasd';
$_ = $s; print "<$_>\n";
$_ = $s; s/(\\[\\n])/$1/g; print "<$_>\n";
print "\n";
$_ = $s; s/(\\[\\n])/qq{$1}/g; print "<$_>\n"; # 1
$_ = $s; s/(\\[\\n])/qq{$1}/ge; print "<$_>\n"; # 3
print "\n";
$_ = $s; s/(\\[\\n])/qq{qq{$1}}/g; print "<$_>\n";
$_ = $s; s/(\\[\\n])/qq{qq{$1}}/ge; print "<$_>\n"; # 2
$_ = $s; s/(\\[\\n])/qq{qq{$1}}/gee; print "<$_>\n"; # 4

Сравните выводы 1 и 2, а затем то, что с ними сделали 3 и 4. smile

Добавлено @ 14:10
nitr, дык я тоже как пример.. А что касается первых трёх постов, так я и не встревал, так как не мог чётко сформулировать задачу... А так, в ходе многочисленных рассуждений прояснилось... smile
1one, perl не пакостит! просто в одинарных кавычках он заменяет только \\ и \', \n он не знает и оставляет как есть. smile

Автор: 1one 27.6.2007, 14:43
Цитата(JAPH @ 27.6.2007,  14:06)
Сравните выводы 1 и 2, а затем то, что с ними сделали 3 и 4. smile

в общем, работает на основе того, что eval от, например, qq(qq(\\\\)) дает нужный результат. Причем qq начинают интерполироваться из внутренних скобок самые первые..

Автор: JAPH 27.6.2007, 15:11
В смысле? Внешние qq - оператор, внутренние - строка...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)