सबसे पहले, आपको अपने पैटर्न से प्रारंभ और अंत तारों की सभी घटनाएं मिलनी होंगी। फिर आपको यह पता लगाना होगा कि कौन से टैग एक साथ फिट हैं (अगर स्ट्रिंग स्ट्रिंग से पहले एंड स्ट्रिंग आती है या एक ही स्थिति में होती है और इसलिए छूती है तो वे फिट नहीं होते हैं)। तो आप अपने टैग जेनरेट कर सकते हैं और अपनी आउटपुट स्ट्रिंग में डाल सकते हैं। ध्यान दें कि आपको अपनी स्थिति में सम्मिलित वर्णों की संख्या जोड़ने की आवश्यकता है, क्योंकि टैग डालने के दौरान स्ट्रिंग की लंबाई बदल रही है। साथ ही, आपको टैग डालने से पहले टैग को क्रमबद्ध करना होगा, अन्यथा गणना करने के लिए यह बहुत जटिल हो जाएगा, आपको पदों को कितनी दूर स्थानांतरित करना होगा। रूबी में एक संक्षिप्त उदाहरण दिया गया है:
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
संपादित करें: जोड़ा परीक्षण और कोड
बैश इस कार्य को लागू करने के लिए एक खराब विकल्प होगा, यह किया जा सकता है लेकिन जटिलता अधिक होगी। पर्ल इस नौकरी के लिए बहुत उपयुक्त है क्योंकि इसे कुछ हद तक इस तरह के कार्यों के लिए बनाया गया था। – msw
आवश्यकताओं को बहुत कम निर्दिष्ट किया गया है। 'सीएटी ... ट्री ... सीएटी ... ट्री 'के साथ क्या होता है। क्या पहला 'सीएटी' दो 'ट्री' से मेल खाता है? या 'सीएटी' हस्तक्षेप का दूसरा मौका है? क्या दो 'सीएटी' शेयरों को 'ट्री' को समाप्त कर सकते हैं? परिणाम 'सीएटी \ प्रारंभ {1} \ प्रारंभ {2} ... \ end {1} ट्री ... सीएटी \ शुरू {3} ... \ end {2} \ end {3} ट्री' होना चाहिए? – Kaz
मैंने टैग अपडेट किए हैं। बाश, पर्ल, पायथन 2.7, और रूबी सभी ठीक होंगे, जब तक वे यूटीएफ -8 में विदेशी पात्रों को संभाल सकें। किसी भी समय एक ही पंक्ति पर एक मैच मिलता है, इसलिए आप जो परिणाम दिखाते हैं वह आदर्श होगा। – Village