Поиск и маркировка парных узоров на линии - PullRequest
7 голосов
/ 12 марта 2012

Мне нужно найти и отметить шаблоны, которые разбиты где-то на строке.Вот сокращенный список образцов шаблонов, которые помещены в отдельный файл, например:

CAT,TREE
LION,FOREST
OWL,WATERFALL

Соответствие появляется, если элемент из столбца 2 появляется после и в той же строке, что и элемент из столбца 1Например:

THEREISACATINTHETREE. (matches)

Соответствие не отображается, если элемент из столбца 2 появляется первым в строке, например:

THETREEHASACAT. (does not match)

Кроме того, соответствие не отображается, если элемент из столбца 1 и2 прикосновения, например:

THECATTREEHASMANYBIRDS. (does not match)

После того, как найдено какое-либо совпадение, мне нужно отметить его \start{n} (появляется после элемента столбца 1) и \end{n} (появляется перед элементом столбца 2),где n - простой счетчик, который увеличивается каждый раз, когда найдено любое совпадение.Например:

THEREISACAT\start{1}INTHE\end{1}TREE.

Вот более сложный пример:

THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.

Это становится:

THECAT\start{1}ANDLION\start{2}LEFTTHE\end{2}FORESTANDMETANDOWL\start{3}INA\end{1}TREENEARTHE\end{3}WATERFALL.

Иногда в одном и том же месте встречаются несколько совпадений:

 THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.

Это становится:

 THECAT\start{1}\start{2}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORT\end{2}TREES.
  • В файле нет пробелов.
  • В нем появляется много нелатинских символов.
  • Сопоставление шаблонов нужно искать только в одной строке (например, «CAT» в строке 1 никогда не совпадает с «TREE», найденным в строке 2, так как они находятся в разных строках).1038 * Как я могу найти эти совпадения и пометить их таким образом?

Ответы [ 7 ]

6 голосов
/ 15 марта 2012

Вот способ Perl сделать это:

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;

# couples of patterns to search for
my @patterns = (
    ['CAT', 'TREE'],
    ['LION', 'FOREST'],
    ['OWL', 'WATERFALL'],
);

# loop over all sentences
while (my $line = <DATA>) {
    chomp $line;    #remove linefeed
    my $count = 1;  #counter of start/end
    foreach my $pats (@patterns) {
        #$p1=first pattern, $p2=second
        my ($p1, $p2) = @$pats;

        #split on patterns, keep them, remove empty
        my @s = grep {$_} split /($p1|$p2)/, $line;

        #$start=position where to put the \start
        #$end=position where to pt the \end
        my ($start, $end) = (undef, undef);

        #loop on all elements given by split
        for my $i (0 .. $#s) {
            # current element
            my $cur = $s[$i];

            #if = first pattern, keep its position in the array
            if ($cur eq $p1) {
                $start = $i;
            }

            #if = second pattern, keep its position in the array
            if ($cur eq $p2) {
                $end = $i;
            }

            #if both are defined and second pattern after first pattern
            # insert \start and \end
            if (defined($start) && defined($end) && $end > $start + 1) {
                $s[$start] .= "\\start{$count}";
                $s[$end] = "\\end{$count}" . $s[$end];
                undef $end;
                $count++;
            }
        }
        # recompose the line
        $line = join '', @s;
    }
    say $line;
}

__DATA__
THETREEHASACAT. (does not match)
THECATTREEHASMANYBIRDS. (does not match)
THEREISACATINTHETREE.
THECATANDLIONLEFTTHEFORESTANDMETANDOWLINATREENEARTHEWATERFALL.
THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.
CAT...TREE...CAT...TREE

вывод:

THETREEHASACAT. (does not match)
THECATTREEHASMANYBIRDS. (does not match)
THEREISACAT\start{1}INTHE\end{1}TREE.
THECAT\start{1}ANDLION\start{2}LEFTTHE\end{2}FORESTANDMETANDOWL\start{3}INA\end{1}TREENEARTHE\end{3}WATERFALL.
THECAT\start{1}\start{2}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORT\end{2}TREES.
CAT\start{1}...\end{1}TREE...CAT\start{2}...\end{2}TREE
5 голосов
/ 16 марта 2012

Проверьте это (Рубин): ​​

#!/usr/bin/env ruby
patterns = [
  ['CAT', 'TREE'],
  ['LION', 'FOREST'],
  ['OWL', 'WATERFALL']
]

lines = [
  'THEREISACATINTHETREE.',
  'THETREEHASACAT.',
  'THECATTREEHASMANYBIRDS.',
  'THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.',
  'THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.',
  'CAT...TREE...CAT...TREE'
]

lines.each do |line|
  puts line
  matches = Hash.new{|h,e| h[e] = [] }
  match_indices = []
  patterns.each do |first,second|
    offset = 0
    while new_offset = line.index(first,offset) do
      # map second element of the pattern to minimal position it might be matched
      matches[second] << new_offset + first.size + 1
      offset = new_offset + 1
    end
  end
  global_counter = 1
  matches.each do |second,offsets|
    offsets.each do |offset|
      second_offset = offset
      while new_offset = line.index(second,second_offset) do
        # register the end index of the first pattern and 
        # the start index of the second pattern with the global match count
        match_indices << [offset-1,new_offset,global_counter]
        second_offset = new_offset + 1
        global_counter += 1
      end
    end
  end
  indices = Hash.new{|h,e| h[e] = ""}
  match_indices.each do |first,second,global_counter|
    # build the insertion string for the string positions the 
    # start and end tags should be placed in
    indices[first] << "\\start{#{global_counter}}"
    indices[second] << "\\end{#{global_counter}}"
  end
  inserted_length = 0
  indices.sort_by{|k,v| k}.each do |position,insert|
    # insert the tags at their positions
    line.insert(position + inserted_length,insert)
    inserted_length += insert.size
  end
  puts line
end

Результат

THEREISACATINTHETREE.
THEREISACAT\start{1}INTHE\end{1}TREE.
THETREEHASACAT.
THETREEHASACAT.
THECATTREEHASMANYBIRDS.
THECATTREEHASMANYBIRDS.
THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.
THECAT\start{1}ANDLION\start{2}LEFTTHE\end{2}FORESTANDMETANDOWL\start{3}IN\end{1}TREENEARTHE\end{3}WATERFALL.
THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.
THECAT\start{1}\start{2}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORT\end{2}TREES.
CAT...TREE...CAT...TREE
CAT\start{1}\start{2}...\end{1}TREE...CAT\start{3}...\end{2}\end{3}TREE

РЕДАКТИРОВАТЬ

Я вставил несколько комментариев и уточнил некоторые переменные.

2 голосов
/ 21 марта 2012

Во-первых, вы должны найти все вхождения начальной и конечной строк в ваших шаблонах.Затем вам нужно выяснить, какие теги подходят друг другу (они не подходят, если конечная строка находится перед начальной строкой или находится в той же позиции и, следовательно, касается).затем вы можете сгенерировать ваши теги и вставить в вашу строку вывода.обратите внимание, что вам нужно добавить количество вставленных символов в ваши позиции, потому что длина строки меняется при вставке тегов.Кроме того, вы должны отсортировать теги по позициям перед их вставкой, иначе было бы очень сложно вычислить, как далеко вы должны сдвинуть позиции.Вот короткий пример на Ruby:

patterns = [['CAT','TREE'], ['LION','FOREST'], ['OWL','WATERFALL']]
strings = ['THEREISACATINTHETREE.', 'THETREEHASACAT.', 'THECATTREEHASMANYBIRDS.', 'THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.', 'THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.', 'ACATONATREEANDANOTHERCATONANOTHERTREE.', 'ACATONATREEBUTNOCATTREE.']

strings.each do |string|
  matches = {}; tags = []
  counter = shift = 0
  output = string.dup

  patterns.each do |sstr,estr|                # loop through all patterns
    posa = []; posb = [];                     #
    string.scan(sstr){posa << $~.end(0)}      # remember found positions and
    string.scan(estr){posb << $~.begin(0)}    # find all valid combinations (next line)
    matches[[sstr,estr]] = posa.product(posb).reject{|s,e|s>=e}
  end

  matches.each do |pat,pos|                   # loop through all matches
    pos.each do |s,e|                         # 
      tags << [s,"\\start{#{counter += 1}}"]  # generate and remember \start{}
      tags << [e,"\\end{#{counter}}"]         # and \end{} tags
    end
  end

  tags.sort.each do |pos,tag|                 # sort and loop through tags
    output.insert(pos+shift,tag)              # insert tag and increment
    shift += tag.chars.count                  # shift by num. of inserted chars
  end

  puts string, output                         # print result
end

Это не красиво, но оно отвечает всем вашим требованиям.Следующий пример, я думаю, немного более читабелен и пригоден для повторного использования, и он реализован как класс Ruby с соответствующими модульными тестами, чтобы гарантировать его работу:

class PatternMarker
  require 'english'

  attr_reader :input, :output, :matches

  def initialize patterns
    @patterns = patterns
    raise ArgumentError, 'no patterns given' unless @patterns.any?
    @patterns.each do |p|
      raise ArgumentError, 'every pattern must have exactly two strings' unless p.count == 2
    end
  end

  def parse input
    @input = input.dup
    match_patterns
    generate_output
    self
  end

  def match?
    @matches.any?
  end

private

  def match_patterns
    @matches = {}
    @patterns.each do |start_str,end_str|
      pos = { :start => [], :end => [] }
      @input.scan(start_str){ pos[:start] << $LAST_MATCH_INFO.end(0)   }
      @input.scan(end_str  ){ pos[:end]   << $LAST_MATCH_INFO.begin(0) }
      @matches[[start_str,end_str]] = pos[:start].product(pos[:end])
      @matches[[start_str,end_str]].reject!{ |s,e| e <= s }
      @matches.reject!{ |p,pos| pos.none? }
    end
  end

  def generate_output
    tags = []
    counter = shift = 0
    @output = @input.dup

    @matches.each do |pattern,positions|
      positions.each do |s,e|
        counter += 1
        tags << [s, "\\start{#{counter}}"]
        tags << [e, "\\end{#{counter}}"  ]
      end
    end

    tags.sort!.each do |position,tag|
      @output.insert(position+shift,tag)
      shift += tag.chars.count
    end
  end
end

в действии:

patterns = [
  ['CAT' , 'TREE'     ],
  ['LION', 'FOREST'   ],
  ['OWL' , 'WATERFALL']
]

strings = [
  'THEREISACATINTHETREE.',
  'THETREEHASACAT.',
  'THECATTREEHASMANYBIRDS.',
  'THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.',
  'THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.',
  'ACATONATREEANDANOTHERCATONANOTHERTREE.',
  'ACATONATREEBUTNOCATTREE.'
]

marker = PatternMarker.new(patterns)

strings.each do |string|
  marker.parse(string)

  puts "input: #{marker.input}"

  if marker.match?
    puts "output: #{marker.output}"
  else
    puts "(does not match)"
  end
  puts
end

вывод:

input: THEREISACATINTHETREE.
output: THEREISACAT\start{1}INTHE\end{1}TREE.

input: THETREEHASACAT.
(does not match)

input: THECATTREEHASMANYBIRDS.
(does not match)

input: THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.
output: THECAT\start{1}ANDLION\start{2}LEFTTHE\end{2}FORESTANDMETANDOWL\start{3}IN\end{1}TREENEARTHE\end{3}WATERFALL.

input: THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.
output: THECAT\start{1}\start{2}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORT\end{2}TREES.

input: ACATONATREEANDANOTHERCATONANOTHERTREE.
output: ACAT\start{1}\start{2}ONA\end{1}TREEANDANOTHERCAT\start{3}ONANOTHER\end{2}\end{3}TREE.

input: ACATONATREEBUTNOCATTREE.
output: ACAT\start{1}\start{2}ONA\end{1}TREEBUTNOCAT\end{2}TREE.

тесты:

require 'test/unit'

class TestPatternMarker < Test::Unit::TestCase
  def setup
    @patterns = [
      ['CAT' , 'TREE'     ],
      ['LION', 'FOREST'   ],
      ['OWL' , 'WATERFALL']
    ]

    @marker = PatternMarker.new(@patterns)
  end

  def test_should_parse_simple
    @marker.parse 'THEREISACATINTHETREE.'
    assert @marker.match?
    assert_equal 'THEREISACAT\start{1}INTHE\end{1}TREE.', @marker.output
  end

  def test_should_parse_reverse
    @marker.parse 'THETREEHASACAT.'
    assert !@marker.match?
    assert_equal @marker.input, @marker.output
  end

  def test_should_parse_touching
    @marker.parse 'THECATTREEHASMANYBIRDS.'
    assert !@marker.match?
    assert_equal @marker.input, @marker.output
  end

  def test_should_parse_multiple_patterns
    @marker.parse 'THECATANDLIONLEFTTHEFORESTANDMETANDOWLINATREENEARTHEWATERFALL.'
    assert @marker.match?
    assert_equal 'THECAT\start{1}ANDLION\start{2}LEFTTHE\end{2}FORESTANDMETANDOWL\start{3}INA\end{1}TREENEARTHE\end{3}WATERFALL.', @marker.output
  end

  def test_should_mark_multiple_matches_at_same_place
    @marker.parse 'THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.'
    assert @marker.match?
    assert_equal 'THECAT\start{1}\start{2}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORT\end{2}TREES.', @marker.output
  end

  def test_should_mark_all_possible_matches
    @marker.parse 'CATFOOTREEFOOCATFOOTREE.'
    assert @marker.match?
    assert_equal 'CAT\start{1}\start{2}FOO\end{1}TREEFOOCAT\start{3}FOO\end{2}\end{3}TREE.', @marker.output
  end

  def test_should_accept_input
    @marker.parse 'CATINTREE'
    assert @marker.match?
    assert_equal 'CATINTREE', @marker.input
    @marker.parse 'FOOBAR'
    assert !@marker.match?
    assert_equal 'FOOBAR', @marker.input
  end

  def test_should_only_accept_valid_patterns
    assert_raise ArgumentError do PatternMarker.new([])                                end
    assert_raise ArgumentError do PatternMarker.new(['FOO','BAR'])                     end
    assert_raise ArgumentError do PatternMarker.new(['FOO','BAR'],['FOO','BAR','BAZ']) end
    assert_raise ArgumentError do PatternMarker.new(['FOO','BAR'],['BAZ'])             end
    assert_nothing_raised      do PatternMarker.new([['FOO','BAR']])                   end
  end
end

тестовый вывод:

Loaded suite pattern
Started
........
Finished in 0.003910 seconds.

8 tests, 21 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 31173

редактирование: добавлены тесты и упрощены некоторые коды

1 голос
/ 22 марта 2012

Вот мое решение в печально не очень популярном Python.

patterns = [u'CAT,TREE', u'LION,FOREST', u'OWL,WATERFALL']

strings = [u'THEREISACATINTHETREE.',
           u'THETREEHASACAT.',
           u'THECATTREEHASMANYBIRDS.',
           u'THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.',
           u'THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.',
           u'ACATONATREEANDANOTHERCATONANOTHERTREE.',
           u'ACATONATREEBUTNOCATTREE.' ]

def findMatch(needles, haystack, label):
    needles = needles.split(',')
    matches = haystack.split(needles[0])

    if len(matches) > 1:
        submatches = matches[1].split(needles[1])

        if len(submatches) > 1:
            return u''.join([matches[0], needles[0], u'\\start{'+label+'}', submatches[0], u'\\end{'+label+'}', needles[1], submatches[1]])

    return False

for s in strings:
    i = 0
    res = s
    for pat in patterns:
        i = i + 1
        temp = findMatch(pat, res, str(i))

        if (temp):
            res = temp

    print ('searching in '+s+' yields '+res).encode('utf-8')
1 голос
/ 22 марта 2012

Вот один полностью в bash (без внешних команд). Не слишком сложно! Ожидает входные строки на stdin.

#/bin/bash

words=("CAT TREE" "LION FORREST" "OWL WATERFALL")

function doit () {
  if [[ "$line" =~ (.*)$word1(.*)$word2(.*) ]]; then
    line="${BASH_REMATCH[1]}$alt_w1\\start{$count}${BASH_REMATCH[2]}$word2\\end{$count}${BASH_REMATCH[3]}"
    (( count += 1 ))
    doit
  elif [[ "$line" =~ $alt_w1 ]]; then
    line=${line//$alt_w1/$word1}
    [[ "$line" =~ (.*)$word2(.*) ]]
    line="${BASH_REMATCH[1]}$alt_w2${BASH_REMATCH[2]}"
    doit
  elif [[ "$line" =~ $alt_w2 ]]; then
    line=${line//$alt_w2/$word2}
  fi
}

while read line; do
  count=1
  for pair in "${words[@]}"; do
    word1=${pair% *}
    word2=${pair#* }
    alt_w1="${word1:0:1}XYZZYX${word1:1}"
    alt_w2="${word2:0:1}XYZZYX${word2:1}"
    doit
  done
  echo "$line"
done

Предположения:

  1. Текст никогда не будет содержать "XYZZYX" (строку можно изменить).
  2. Слова никогда не будут содержать символы, используемые в регулярных выражениях.
    • например. . * [ ] ^ $ +
    • (это нормально для тех, кто стоит в строках).
  3. Слова всегда будут длиной не менее двух символов.
  4. Слова никогда не будут подстроками других слов, которые вы ищете.
    • например. cat и cattle.
    • На самом деле, это может сработать, но результат может быть ужасным.
1 голос
/ 13 марта 2012

Вот частичный ответ. Он соответствует всем вашим требованиям, кроме последнего, который не имеет единого простого решения. Я оставлю это для вас, чтобы выяснить: -)

Я выбрал подход на основе правил вместо регулярных выражений. В предыдущих аналогичных проектах я обнаружил, что простые парсеры на основе правил легче обслуживать, переносить и, как правило, быстрее, чем регулярные выражения. Я не использовал никаких действительно специфичных для Ruby функций, поэтому он должен быть легко переносим на Python или Perl. Он даже должен быть переносим на C без особых усилий.

patterns = [
  ['CAT', 'TREE'],
  ['LION', 'FOREST'],
  ['OWL', 'WATERFALL']
]

lines = [
  'THEREISACATINTHETREE.',
  'THETREEHASACAT.',
  'THECATTREEHASMANYBIRDS.',
  'THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL.',
  'THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.'
]

newlines = []

START_TAG_LENGTH = 9
END_TAG_LENGTH = 7

lines.each do |line|

  newline = line.dup
  before = {}
  n = 1

  patterns.each do |pair|

    a = 0

    matches = [[], []]
    len = pair[0].length

    pair.each do |pattern|
      b = 0
      while (c = line.index(pattern, b))
        matches[a] << c
        b = c + 1
      end
      break if b == 0 && a > 0
      a += 1
    end

    matches[0].each_with_index do |d, f|
      bd = 0; be = 0
      e = matches[1][f]
      next if (d > e) || (d + len == e)
      d = d + len
      before.each { |g, h| bd += h if g <= d }
      newline.insert(d + bd, "\\start{#{n}}")
      before[d] ||= 0
      before[d] += START_TAG_LENGTH
      before.each { |g, h| be += h if g <= e }
      newline.insert(e + be, "\\end{#{n}}")
      before[e] ||= 0
      before[e] += END_TAG_LENGTH
    end

    n += 1

  end

  newlines << newline

end

puts newlines

Выход:

THEREISACAT\start{1}INTHE\end{1}TREE.
THETREEHASACAT.
THECATTREEHASMANYBIRDS.
THECAT\start{1}ANDLION\start{2}LEFTTHE\end{2}FORESTANDMETANDOWL\start{3}IN\end{1}TREENEARTHE\end{3}WATERFALL.
THECAT\start{1}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORTTREES.

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

На заметку, просто любопытно, зачем ты это используешь?

0 голосов
/ 21 марта 2012

Вот мой подход PERL. Это быстро и грязно.

Может быть, гораздо лучше, если бы я использовал Marpa для разбора не регулярных выражений.

Во всяком случае, это делает работу.

use strict;
use Test::More;
use Data::Dumper;

# patterns to search for
my @patterns = (
    'CAT,TREE',
    'LION,FOREST',
    'OWL,WATERFALL',
);
#lines
my @lines = qw(
THEREISACATINTHETREE.
THETREEHASACAT.
THECATTREEHASMANYBIRDS.
THECATANDLIONLEFTTHEFORESTANDMETANDOWLINATREENEARTHEWATERFALL.
THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES.
THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREESORBIGTREES.
);


my @expected_output = (
'THEREISACAT\start{1}INTHE\end{1}TREE.',
'Does not Match',
'Does not Match',
'THECAT\start{1}ANDLION\start{2}LEFTTHE\end{2}FORESTANDMETANDOWL\start{3}INA\end{1}TREENEARTHE\end{3}WATERFALL.',
'THECAT\start{1}\start{2}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORT\end{2}TREES.',
'THECAT\start{1}\start{2}\start{3}DOESNOTLIKETALL\end{1}TREES,BUTINSTEADLIKESSHORT\end{2}TREESORBIG\end{3}TREES.',
);

#is(check_line($lines[0]),$expected_output[0]);die;

my $no=0;
for(my $i=0;$i<scalar(@lines );$i++){   
    is(check_line($lines[$i]),$expected_output[$i]);
    $no++;
}
done_testing( $no );

sub check_line{
    my $in      = shift;
    my $out = '';
    my $match = 1;
    foreach my $pattern_line (@patterns){
        my ($first,$second) = split(/,/,$pattern_line);
        #warn "$first,$second,$in\n";
        if ($in !~ m#$first.+?$second#is){
            next;
        }
        #matched    

        while ($in =~ s#($first)(.+?)($second)#$1\\start\{$match\}$2\\end\{$match\}_SECOND_#is){
            $match++;
            #warn "Found match: $match\n";
        }
        $in =~ s#_SECOND_#$second#gis;
        #$in =~ s#\\start\{(\d+)\}\\start\{(\d+)\}#\\start\{$2\}\\start\{$1\}#gis;
        my ($end,$start) = $in =~ m#\\start\{(\d+)\}(?:\\start\{(\d+)\})+#gis;

        my $stmp = join("",map {"\\start\{$_\}"} ($start..$end));
        #print Dumper($in,$start,$end,$stmp);
        $in =~ s#\\start\{($end)\}.*?\\start\{($start)\}#$stmp#is;


    }
    return 'Does not Match' if $match ==1;
    $out = $in;
    return $out;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...