2012-03-12 6 views
7

पर जोड़े गए पैटर्न को खोजना और चिह्नित करना मुझे किसी रेखा पर कहीं भी विभाजित पैटर्न खोजने और चिह्नित करने की आवश्यकता है। यहाँ नमूना पैटर्न का एक छोटा सूची जो एक अलग फाइल में रखा जाता है, जैसे है:लाइन

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 एक साधारण काउंटर जो बढ़ जाती है के साथ चिह्नित करने की आवश्यकता किसी भी समय कोई मैच पाया जाता है। उदाहरण के लिए:

THECATANDLIONLEFTTHEFORESTANDMETANDOWLINTREENEARTHEWATERFALL. 

यह हो जाता है::

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

यहाँ एक अधिक जटिल उदाहरण है

THECATDOESNOTLIKETALLTREES,BUTINSTEADLIKESSHORTTREES. 

:

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. 
  • फ़ाइल में कोई रिक्त स्थान हैं।
  • फ़ाइल में कई गैर-लैटिन वर्ण दिखाई देते हैं।
  • पैटर्न मिलान केवल उसी पंक्ति पर पाए जाते हैं (उदाहरण के लिए लाइन 1 पर "सीएटी" कभी लाइन 2 पर पाए गए "ट्री" से मेल नहीं खाता है, क्योंकि वे अलग-अलग लाइनों पर हैं)।

मैं इन मैचों को कैसे ढूंढ सकता हूं और उन्हें इस तरह से चिह्नित कर सकता हूं?

+3

बैश इस कार्य को लागू करने के लिए एक खराब विकल्प होगा, यह किया जा सकता है लेकिन जटिलता अधिक होगी। पर्ल इस नौकरी के लिए बहुत उपयुक्त है क्योंकि इसे कुछ हद तक इस तरह के कार्यों के लिए बनाया गया था। – msw

+3

आवश्यकताओं को बहुत कम निर्दिष्ट किया गया है। 'सीएटी ... ट्री ... सीएटी ... ट्री 'के साथ क्या होता है। क्या पहला 'सीएटी' दो 'ट्री' से मेल खाता है? या 'सीएटी' हस्तक्षेप का दूसरा मौका है? क्या दो 'सीएटी' शेयरों को 'ट्री' को समाप्त कर सकते हैं? परिणाम 'सीएटी \ प्रारंभ {1} \ प्रारंभ {2} ... \ end {1} ट्री ... सीएटी \ शुरू {3} ... \ end {2} \ end {3} ट्री' होना चाहिए? – Kaz

+0

मैंने टैग अपडेट किए हैं। बाश, पर्ल, पायथन 2.7, और रूबी सभी ठीक होंगे, जब तक वे यूटीएफ -8 में विदेशी पात्रों को संभाल सकें। किसी भी समय एक ही पंक्ति पर एक मैच मिलता है, इसलिए आप जो परिणाम दिखाते हैं वह आदर्श होगा। – Village

उत्तर

5

चेक इस बाहर (रूबी):

#!/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 

EDIT

मैंने कुछ टिप्पणियां डालीं और कुछ चर को स्पष्ट किया।

1

यहां आंशिक उत्तर दिया गया है। यह आखिरी एक को छोड़कर आपकी सभी आवश्यकताओं को फिट करता है, जिसमें कोई भी सरल समाधान नहीं है। मैं आपके लिए यह पता लगाने के लिए छोड़ दूंगा :-)

मैंने नियमित अभिव्यक्तियों के बजाय नियम-आधारित दृष्टिकोण चुना है। मैंने पिछले समान परियोजनाओं में पाया है कि सरल नियम-आधारित पार्सर्स नियमित रूप से अभिव्यक्तियों से अधिक आसानी से रखरखाव योग्य, पोर्टेबल और आमतौर पर तेज़ होते हैं। मैंने यहां वास्तव में रूबी-विशिष्ट विशेषताओं का उपयोग नहीं किया है, इसलिए इसे पाइथन या पर्ल के लिए आसानी से पोर्टेबल होना चाहिए। इसे बिना किसी प्रयास के सी को पोर्टेबल भी होना चाहिए।

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. 

सूचना यह पिछले एक पर असफल रहा। हालांकि, आपको एक अच्छा सिर शुरू करना चाहिए, हालांकि। अगर आपको यह पता लगाने में मदद की ज़रूरत है कि कुछ कोड क्या करता है, तो संकोच न करें।

एक तरफ ध्यान दें, बस उत्सुक होने के कारण, आप इसका क्या उपयोग कर रहे हैं?

6

यहाँ एक पर्ल तरीका यह करने के लिए है:

#!/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 
+1

अच्छा। मेरे संस्करण की तुलना में निश्चित रूप से क्लीनर। – user2398029

+1

लेकिन इस एल्गोरिदम में 'सीएटी ... ट्री ... सीएटी ... ट्री' ठीक से कवर नहीं है, मुझे डर है। –

+1

इसके अलावा (हालांकि विवरण में उल्लिखित नहीं है), यदि पैटर्न तत्व हैं जो ओवरलैप होते हैं, तो बाद में लागू पैटर्न को मिलान नहीं किया जाएगा। –

2

सबसे पहले, आपको अपने पैटर्न से प्रारंभ और अंत तारों की सभी घटनाएं मिलनी होंगी। फिर आपको यह पता लगाना होगा कि कौन से टैग एक साथ फिट हैं (अगर स्ट्रिंग स्ट्रिंग से पहले एंड स्ट्रिंग आती है या एक ही स्थिति में होती है और इसलिए छूती है तो वे फिट नहीं होते हैं)। तो आप अपने टैग जेनरेट कर सकते हैं और अपनी आउटपुट स्ट्रिंग में डाल सकते हैं। ध्यान दें कि आपको अपनी स्थिति में सम्मिलित वर्णों की संख्या जोड़ने की आवश्यकता है, क्योंकि टैग डालने के दौरान स्ट्रिंग की लंबाई बदल रही है। साथ ही, आपको टैग डालने से पहले टैग को क्रमबद्ध करना होगा, अन्यथा गणना करने के लिए यह बहुत जटिल हो जाएगा, आपको पदों को कितनी दूर स्थानांतरित करना होगा। रूबी में एक संक्षिप्त उदाहरण दिया गया है:

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 

यह सुंदर नहीं है, लेकिन यह आपकी सभी आवश्यकताओं को पूरा करता है। अगले उदाहरण में थोड़ा और अधिक पठनीय है और पुन: प्रयोज्य मुझे लगता है कि और यह इसी यूनिट टेस्ट यह सुनिश्चित करने के लिए के साथ एक रूबी वर्ग के रूप में महसूस किया है काम करता है:

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 

उत्पादन:

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 

कार्रवाई में

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 [email protected]? 
    assert_equal @marker.input, @marker.output 
    end 

    def test_should_parse_touching 
    @marker.parse 'THECATTREEHASMANYBIRDS.' 
    assert [email protected]? 
    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 [email protected]? 
    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 

संपादित करें: जोड़ा परीक्षण और कोड

0

यहाँ मेरी PERL दृष्टिकोण है में से कुछ को सरल बनाया। यह तेज़ और गंदा है।

यह शायद बेहतर होगा अगर मैंने मार्पा को रीजक्सप्स को पार्सिंग के लिए इस्तेमाल नहीं किया था।

वैसे भी, यह नौकरी करता है।

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; 
} 
+2

हाय, अगर आप मेरे समाधान को कम करते हैं, तो क्या आप टिप्पणी करना चाहते हैं, क्यों? – user1126070

1

यहां एक पूरी तरह से बैश (कोई बाहरी आदेश नहीं) है। बहुत कठोर नहीं! यह 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
    • असल में, यह काम कर सकता है, लेकिन परिणाम नरक के रूप में भ्रमित हो जाएगा।
+0

नियमित अभिव्यक्तियों में उपयोग किए जाने वाले वर्ण कौन से वर्ण नहीं दिख सकते हैं? क्या यह समस्या है यदि नियमित अभिव्यक्तियों में उपयोग किए गए उन वर्णों में से कोई भी इनपुट लाइनों में दिखाई देता है?इसका अर्थ क्या है, "शब्द कभी दूसरे शब्दों के सबस्ट्रिंग नहीं होंगे?" – Village

+1

'कभी भी अन्य शब्दों के सबस्ट्रिंग्स' नहीं होने का मतलब है कि यदि आप 'बिल्ली' से मेल खाना चाहते हैं तो आप 'मवेशी' से भी मेल खाते हैं। यदि आपके पास शब्द विभाजक नहीं हैं तो यह अपरिहार्य है। – jimw

+1

दाएं, और यदि आप "मवेशी" और "बिल्ली" दोनों से मेल खाना चाहते हैं, तो आपको या तो "बिल्ली \ प्रारंभ {2} tle \ start {1}", या बस "बिल्ली \ प्रारंभ {1} टेल" मिलेगा, जिस पर आप पहली बार खोज करते हैं। – ams

1

यहाँ उदासी बहुत लोकप्रिय नहीं पायथन में मेरे समाधान है।

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')