#!/usr/bin/perl
my $s = "Основное {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{Значение 4.1|Значение 4.2|Значение 4.3|} Значение 5} Основное 2";
recursivePrint(parse($s));
sub parse
{
my $str = shift;
my $cur = [];
my @stack = ();
my $tok = '';
while($str =~ /(.)/sg)
{
my $c = $1;
if($c !~ /^[{}\|]*$/) {
$tok .= $c;
next;
}
if($tok ne '') {
push(@$cur, trim($tok));
$tok = '';
}
if($c eq '{')
{
push(@stack, $cur);
$cur = [];
}
elsif($c eq '}')
{
if(@stack) {
my $a = pop(@stack);
push(@$a, $cur);
$cur = $a;
} else {
last;
}
}
}
## Добавлено.
while(@stack) {
my $a = pop(@stack);
push(@$a, $cur);
$cur = $a;
}
return $cur;
}
sub trim
{
my $s = shift;
$s =~ s/^\s+|\s$//g;
return $s;
}
sub recursivePrint
{
local $level = 0;
&_recursivePrint;
}
sub _recursivePrint
{
my($arr) = @_;
my $suff1 = "\t" x $level;
$level++;
my $suff2 = "\t" x $level;
print $suff1, "{\n";
foreach (@$arr)
{
if(ref $_ eq 'ARRAY') {
_recursivePrint($_);
} else {
print $suff2, $_, "\n";
}
}
print $suff1, "}\n";
$level--;
}
Помогите составить регулярное выражение на PHP
Встал довольно срочный вопрос. В общем никак немогу составить правильно регулярное выражение на PHP.
Суть такая.
Есть некое количество переменных значений в фиг. скобках, в свою очередь в этих скобках могут быть ещё фигурные скобки. Таким образом, получается вложеннось. Но вложенность не может быть больше 1-го уровня, что естественно задачу облегчает. НО. Принципиально важно, чтобы в фиг. скобках вложенными были только фиг. скобки, а не какие другие делимиторы.
Вот пример исходной строки:
Основное {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{Значение 4.1|Значение 4.2|Значение 4.3|} Значение 5} Основное 2
Суть в том, что мне нужно получть отдельно:
- {Значение 1|Значение 2|Значение 3
- {Значение 3.1|Значение 3.2|Значение 3.3|}
- Значение 4
- {Значение 4.1|Значение 4.2|Значение 4.3|}
- Значение 5
и потом уже дальше с ними манипулировать.
Пробую preg_match_all("~\{(.*)\}~isU", $stroka, $fVarsArray, PREG_PATTERN_ORDER)
Где $stroka - исходная строка, $fVarsArray - массив того, что находит.
Но находит не то.
Вместо 1-го значения оно мне выдаёт {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|}, а не {Значение 1|Значение 2|Значение 3
Подскажите, как мне быть.
Хотя поидее так возможно сделать. В той же программе Zend Studio в редакторе кода правильно определяется какая открывающая скобка к какой именно закрывающей относится. В принципе, похожая ерунда. Но как их определить? Или лучше не парится, а просто другие знаки использовать для выделения вложенной части?
Думаю тут нужно делать без регулярных выражений - считать скобки.
{Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} }
или
{Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{тыры-пыры...}}
или
{Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{тыры-пыры...} знач 5 {тыры-пыры..пырыры} знач n}
ну и т.д.
Вот я и бью голову целые 2 дня уже. :(
Можешь и с регулярным выражением, только скобки тебе все равно считать прейдется.
Цитата: Fobos
Здравствуйте!
Встал довольно срочный вопрос. В общем никак немогу составить правильно регулярное выражение на PHP.
Суть такая.
Есть некое количество переменных значений в фиг. скобках, в свою очередь в этих скобках могут быть ещё фигурные скобки. Таким образом, получается вложеннось. Но вложенность не может быть больше 1-го уровня, что естественно задачу облегчает. НО. Принципиально важно, чтобы в фиг. скобках вложенными были только фиг. скобки, а не какие другие делимиторы.
Вот пример исходной строки:
Основное {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{Значение 4.1|Значение 4.2|Значение 4.3|} Значение 5} Основное 2
Суть в том, что мне нужно получть отдельно:
- {Значение 1|Значение 2|Значение 3
- {Значение 3.1|Значение 3.2|Значение 3.3|}
- Значение 4
- {Значение 4.1|Значение 4.2|Значение 4.3|}
- Значение 5
и потом уже дальше с ними манипулировать.
Пробую preg_match_all("~\{(.*)\}~isU", $stroka, $fVarsArray, PREG_PATTERN_ORDER)
Где $stroka - исходная строка, $fVarsArray - массив того, что находит.
Но находит не то.
Вместо 1-го значения оно мне выдаёт {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|}, а не {Значение 1|Значение 2|Значение 3
Подскажите, как мне быть.
Встал довольно срочный вопрос. В общем никак немогу составить правильно регулярное выражение на PHP.
Суть такая.
Есть некое количество переменных значений в фиг. скобках, в свою очередь в этих скобках могут быть ещё фигурные скобки. Таким образом, получается вложеннось. Но вложенность не может быть больше 1-го уровня, что естественно задачу облегчает. НО. Принципиально важно, чтобы в фиг. скобках вложенными были только фиг. скобки, а не какие другие делимиторы.
Вот пример исходной строки:
Основное {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{Значение 4.1|Значение 4.2|Значение 4.3|} Значение 5} Основное 2
Суть в том, что мне нужно получть отдельно:
- {Значение 1|Значение 2|Значение 3
- {Значение 3.1|Значение 3.2|Значение 3.3|}
- Значение 4
- {Значение 4.1|Значение 4.2|Значение 4.3|}
- Значение 5
и потом уже дальше с ними манипулировать.
Пробую preg_match_all("~\{(.*)\}~isU", $stroka, $fVarsArray, PREG_PATTERN_ORDER)
Где $stroka - исходная строка, $fVarsArray - массив того, что находит.
Но находит не то.
Вместо 1-го значения оно мне выдаёт {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|}, а не {Значение 1|Значение 2|Значение 3
Подскажите, как мне быть.
preg_match("/{.*?}/", $stroka, $fVarsArray); вот так должны все скобки выбраться
Цитата: ivtrans
preg_match("/{.*?}/", $stroka, $fVarsArray); вот так должны все скобки выбраться
[offtop]почему народ не читает то, что пишут выше? )[/offtop]
а вложенность за тебя сосед посчитает? ;)
данную задачу, навскидку, можно решить динамическими регулярками, но я не знаю, как оно работает в PHP и работает ли вообще
Вот как выделить главные от внутренних скобок:
Код:
$text = "Основ 1 {Знач 1{3.3|}{} {jhgjhgh} Знач 4{4.3|}ascasc} Основ 2 {Ещё{} кое-что}{Ещё{} кое-что} [] {} {{}}";
$text2= $text;
//Ищем пару скобке.
for ($i=0; $i<=substr_count($text2, '}')-1; $i++)
{
$msoppos = strpos($text, '{');
$msclpos = strpos($text, '}');//Находим позицию 1-й }
//Если между откр (::main~ и найденым } количество откр. равно кол-ву закр. подскобок, то принимаем за главную и закрываем (заменяем на усл. знак.), если нет то дальше
$buffer = substr($text, $msoppos+1, $msclpos-$msoppos-1);
//Счит. кол-во { и }
$socnt = substr_count($buffer, '{');
$sccnt = substr_count($buffer, '}');
$ssccnt = substr_count($buffer, '~sub::)');
if ($socnt == $sccnt or $socnt == $ssccnt)//Если количество открывающих и закрывающих внутри равны, то значит наша закрывающая есть главная!!! УРА!!!
{
//Заменяем значения, чтобы к ним уже не возвращаться! Уффффф.
$msoppos = strpos($text, '{');
$text = substr_replace($text, '(::main~', $msoppos, 1);//Заменяем { на (::main~
$msclpos = strpos($text, '}');//Находим позицию 1-й }
$text = substr_replace($text, '~main::)', $msclpos, 1);//Заменяем } на ~main::)
//Теперь все внутренние закр. скобки заменяем на усл. знак. (::sub~
$buffer2 = substr($text, $msoppos, $msclpos-$msoppos);
$buffer3 = str_replace('{', '(::sub~', $buffer2);
$text = str_replace($buffer2, $buffer3, $text);
}
else
{
$text = substr_replace($text, '~sub::)', $msclpos, 1);//Заменяем } на ~main::)
}
}
echo '<b>'.$text.'<br>';
$text2= $text;
//Ищем пару скобке.
for ($i=0; $i<=substr_count($text2, '}')-1; $i++)
{
$msoppos = strpos($text, '{');
$msclpos = strpos($text, '}');//Находим позицию 1-й }
//Если между откр (::main~ и найденым } количество откр. равно кол-ву закр. подскобок, то принимаем за главную и закрываем (заменяем на усл. знак.), если нет то дальше
$buffer = substr($text, $msoppos+1, $msclpos-$msoppos-1);
//Счит. кол-во { и }
$socnt = substr_count($buffer, '{');
$sccnt = substr_count($buffer, '}');
$ssccnt = substr_count($buffer, '~sub::)');
if ($socnt == $sccnt or $socnt == $ssccnt)//Если количество открывающих и закрывающих внутри равны, то значит наша закрывающая есть главная!!! УРА!!!
{
//Заменяем значения, чтобы к ним уже не возвращаться! Уффффф.
$msoppos = strpos($text, '{');
$text = substr_replace($text, '(::main~', $msoppos, 1);//Заменяем { на (::main~
$msclpos = strpos($text, '}');//Находим позицию 1-й }
$text = substr_replace($text, '~main::)', $msclpos, 1);//Заменяем } на ~main::)
//Теперь все внутренние закр. скобки заменяем на усл. знак. (::sub~
$buffer2 = substr($text, $msoppos, $msclpos-$msoppos);
$buffer3 = str_replace('{', '(::sub~', $buffer2);
$text = str_replace($buffer2, $buffer3, $text);
}
else
{
$text = substr_replace($text, '~sub::)', $msclpos, 1);//Заменяем } на ~main::)
}
}
echo '<b>'.$text.'<br>';
Просто заменяет внешние скобки на (::main~ ~main::),
а внутренние на (::sub~ ~sub::).
А дальше уже просто с ними оперировать.
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
Однако мой вариант не универсален и не позволяет учитывать неограниченную вложенность. Но мне по проекту в принципе того и не надо. :) Так, для интереса, было-б замечательно узнать.
Не знаю как на php, но на perl это делается очень просто (если конечно правильно понял задачу :) ):
Код:
<?php
function str_exploding($str) {
// $tt = gettimeofday();
// $time = $tt['sec'] + $tt['usec'] / 1000000;
$strpos = 0;
$result = array();
$i = 0;
while (!empty($str[$strpos])) {
if ($str[$strpos] == '{' or $str[$strpos] == '}') {
$result[$i] = trim($result[$i]);
$i++;
$strpos++;
$result[$i] = '';
}
$result[$i] .= $str[$strpos];
$strpos++;
}
// $tt = gettimeofday();
// $time = ($tt['sec'] + $tt['usec'] / 1000000) - $time;
// $result['time'] = 'Длительность действия: '.sprintf('%.5f', $time);
return $result;
}
$str = 'Основное {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{Значение 4.1|Значение 4.2|Значение 4.3|} Значение 5} Основное 2';
$prs = str_exploding($str);
foreach ($prs as $line) {
echo '- '.$line.'<br />';
}
?>
function str_exploding($str) {
// $tt = gettimeofday();
// $time = $tt['sec'] + $tt['usec'] / 1000000;
$strpos = 0;
$result = array();
$i = 0;
while (!empty($str[$strpos])) {
if ($str[$strpos] == '{' or $str[$strpos] == '}') {
$result[$i] = trim($result[$i]);
$i++;
$strpos++;
$result[$i] = '';
}
$result[$i] .= $str[$strpos];
$strpos++;
}
// $tt = gettimeofday();
// $time = ($tt['sec'] + $tt['usec'] / 1000000) - $time;
// $result['time'] = 'Длительность действия: '.sprintf('%.5f', $time);
return $result;
}
$str = 'Основное {Значение 1|Значение 2|Значение 3 {Значение 3.1|Значение 3.2|Значение 3.3|} Значение 4{Значение 4.1|Значение 4.2|Значение 4.3|} Значение 5} Основное 2';
$prs = str_exploding($str);
foreach ($prs as $line) {
echo '- '.$line.'<br />';
}
?>
- Основное
- Значение 1|Значение 2|Значение 3
- Значение 3.1|Значение 3.2|Значение 3.3|
- Значение 4
- Значение 4.1|Значение 4.2|Значение 4.3|
- Значение 5
- Основное 2
Код:
function str_exploding($str) {
return preg_split('/\s*[{}]\s*/', trim($str));
}
return preg_split('/\s*[{}]\s*/', trim($str));
}