আপনার ভাষায় পিসিআরই প্রয়োগ করুন।


13

দ্রষ্টব্য: নিজে চেষ্টা করার পরে, আমি শীঘ্রই বুঝতে পারি এটি কী ভুল ছিল। তারপরে, আমি নিয়মগুলি কিছুটা সংশোধন করছি।

সর্বনিম্ন প্রয়োজনীয় কার্যকারিতা:

  • ক্যারেক্টার ক্লাস ( ., \w, \W, ইত্যাদি)
  • গুণক ( +, *এবং ?)
  • সাধারণ ক্যাপচার গ্রুপগুলি

আপনার চ্যালেঞ্জটি হ'ল নিম্নলিখিত শর্ত সাপেক্ষে আপনার পছন্দের ভাষায় পিসিআরই প্রয়োগ করা :

  • আপনি আপনার ভাষার স্থানীয় RegEx সুবিধা কোনও উপায়ে ব্যবহার করতে পারবেন না । আপনি তৃতীয় পক্ষের RegEx লাইব্রেরি নাও ব্যবহার করতে পারেন।
  • আপনার প্রবেশদ্বার যতটা পিসিআরই অনুমান বাস্তবায়ন করা উচিত। যতটুকু সম্ভব.
  • আপনার প্রোগ্রামটি ইনপুট, 2 লাইন হিসাবে গ্রহণ করবে:

    • নিয়মিত প্রকাশ
    • এর সাথে মেলে স্ট্রিং ইনপুট
  • আপনার প্রোগ্রামটি এর আউটপুটে নির্দেশ করা উচিত:

    • রেজিএক্স ইনপুট স্ট্রিংয়ের যে কোনও জায়গায় মিলে
    • যে কোনও ক্যাপচারিং গ্রুপের ফলাফল
  • বিজয়ীর এমন প্রবেশিকা হতে হবে যা অনুমানের পরিমাণ কার্যকর করে। যতটুকু সম্ভব. টাই করার ক্ষেত্রে, বিজয়ী সবচেয়ে সৃজনশীল এন্ট্রি হিসাবে আমার দ্বারা বিচার করা হবে।


সম্পাদনা করুন: কয়েকটি জিনিস স্পষ্ট করতে এখানে ইনপুট এবং প্রত্যাশিত আউটপুটের কয়েকটি উদাহরণ রয়েছে:


  • ইনপুট:
^ \ গুলি * (\ W + +) $
         হ্যালো
  • আউটপুট:
ম্যাচগুলি: হ্যাঁ
গ্রুপ 1: 'হ্যালো'

  • ইনপুট:
(\ W + +) @ (\ W + +) (:। \ কম | \ .net)
sam@test.net
  • আউটপুট:
ম্যাচগুলি: হ্যাঁ
গ্রুপ 1: 'সাম'
গ্রুপ 2: 'পরীক্ষা'


এটি একটি চ্যালেঞ্জিং চ্যালেঞ্জ, পিসিআরই এর বৈশিষ্ট্যগুলির পরিমাণ দেওয়া। Recursion, backtracking না, lookahead / গবেষকেরা, ইউনিকোড, শর্তাধীন subpatterns ...
Arnaud লে Blanc,


@ ব্যবহারকারী 300: লক্ষ্যটি যতটা সম্ভব কার্যকর করা to স্পষ্টতই সবকিছু কিছুটা শক্ত হয়ে যেত।
নাথান ওসমান

2
@ জর্জি: আপনি যে বৈশিষ্ট্যগুলি চান তা তালিকাভুক্ত করেন এবং কিছু পরীক্ষার কেস দেবেন, যাতে আমরা সবাই সমতল হয়ে যাই।
মার্কো ডুমিক

1
@ জর্জি: আমি মনে করি @ মারকো নির্দিষ্ট বৈশিষ্ট্যগুলির পরে বা তার চেয়ে বরং আপনি যে সর্বনিম্ন সাবসেটটি লোকদের প্রথমে প্রয়োগ করতে চান। যদিও সামগ্রিকভাবে, পিসিআরই একটি নৈমিত্তিক কোডিং প্রতিযোগিতার পক্ষে খুব কঠিন একটি চ্যালেঞ্জ। আমি এটিকে একটি খুব ছোট, নির্দিষ্ট আর ও উপসেটে পরিবর্তন করার পরামর্শ দিচ্ছি এবং প্রয়োগ করার চ্যালেঞ্জটি করব make
এমটিএনভিউমার্ক

উত্তর:


10

পাইথন

যেহেতু পুরো পিসিআরই বাস্তবায়ন অত্যধিক তাই আমি এর একটি প্রয়োজনীয় উপসেটটি প্রয়োগ করেছি।

সমর্থন |.\.\w\W\s+*()। ইনপুট regexp অবশ্যই সঠিক হতে হবে।

উদাহরণ:

$ python regexp.py 
^\s*(\w+)$
   hello
Matches:     hello
Group 1 hello

$ python regexp.py
(a*)+
infinite loop

$ python regexp.py 
(\w+)@(\w+)(\.com|\.net)
sam@test.net
Matches:  sam@test.net
Group 1 sam
Group 2 test
Group 3 .net

কিভাবে এটা কাজ করে:

বিশদ তত্ত্বের জন্য অটোমাটা থিওরি, ভাষা এবং গণনার এই ভূমিকাটি পড়ুন ।

ধারণাটি হ'ল আসল নিয়মিত অভিব্যক্তিটিকে একটি ননডেটেরিনিস্টিস্ট সসীম অটোমেটাতে (এনএফএ) রূপান্তর করা। আসলে, পিসিআরই নিয়মিত এক্সপ্রেশন হ'ল কমপক্ষে প্রসঙ্গ মুক্ত ব্যাকরণ যার জন্য আমাদের পুশ-ডাউন অটোমেটা প্রয়োজন তবে আমরা নিজেরাই পিসিআরইর একটি উপসেটে সীমাবদ্ধ করব।

সীমাবদ্ধ অটোমেটাসকে নির্দেশিত গ্রাফ দেওয়া হয় যেখানে নোডগুলি রাজ্য, প্রান্তগুলি হ'ল রূপান্তর এবং প্রতিটি ক্রান্তিকরণের একটি মিলে ইনপুট থাকে। প্রাথমিকভাবে আপনি শুরু নোড থেকে শুরু করেন, পূর্বনির্ধারিত। যখনই আপনি এমন একটি ইনপুট পান যা কোনও রূপান্তরটির সাথে মেলে আপনি সেই রূপান্তরটিকে একটি নতুন অবস্থায় নিয়ে যান। আপনি যদি কোনও টার্মিনাল নোডে পৌঁছে থাকেন তবে এটিকে অটোমাতা স্বীকৃত ইনপুট বলে। আমাদের ক্ষেত্রে ইনপুট হল একটি ম্যাচিং ফাংশন যা সত্য ফিরে আসে।

এগুলিকে ননডেটেরিমনস্ট অটোমেটা বলা হয় কারণ কখনও কখনও আরও একই সাথে মিলে যাওয়া ট্রানজিশনগুলি থাকে যা আপনি একই অবস্থা থেকে নিতে পারেন। আমার প্রয়োগে একই রাজ্যে সমস্ত রূপান্তর অবশ্যই একই জিনিসটির সাথে মেলে, তাই আমি গন্তব্যস্থল ( states[dest][0]) এর সাথে মিলিয়ে ফাংশনটি সংরক্ষণ করেছি ।

বিল্ডিং ব্লক ব্যবহার করে আমরা আমাদের রেজিএক্সপিকে একটি সসীম অটোম্যাটাতে রূপান্তর করি। একটি বিল্ডিং ব্লকের একটি প্রারম্ভ নোড ( first) এবং একটি প্রান্ত নোড ( last) থাকে এবং পাঠ্যের সাথে কিছু মিলিয়ে যায় (সম্ভাব্য খালি স্ট্রিং)।

সহজ উদাহরণ অন্তর্ভুক্ত

  • কিছুই মিলছে না: True( first == last)
  • একটি চরিত্রের সাথে মেলে: c == txt[pos]( first == last)
  • স্ট্রিংয়ের সমাপ্তি: পোস্ট == লেন (টেক্সট) (প্রথম == শেষ=)

পরবর্তী টোকেনটি কোথায় মিলবে তা পাঠ্যের ক্ষেত্রেও আপনাকে নতুন অবস্থানের প্রয়োজন হবে।

আরও জটিল উদাহরণগুলি হ'ল (মূল অক্ষরগুলি ব্লকের জন্য দাঁড়ায়)।

  • মিলবে বি +:

    • নোড তৈরি করুন: ইউ, ভি (কিছুই মিলছে না)
    • রূপান্তরগুলি তৈরি করুন: ইউ -> বিফার্স্ট, বিস্ট -> ভি, ভি -> ইউ
    • আপনি যখন নোড পাবেন তখন ইতিমধ্যে আপনার বিয়ের সাথে মিল আছে Then তারপরে আপনার দুটি বিকল্প রয়েছে: আরও এগিয়ে যান, বা আবার বি এর সাথে মেলে দেখার চেষ্টা করুন।
  • মিলবে এ | বি | সি:

    • নোড তৈরি করুন: ইউ, ভি (কিছুই মিলছে না)
    • রূপান্তরগুলি তৈরি করুন: u -> এফার্স্ট, u -> সিফার্স্ট, u -> সিফার্স্ট,
    • রূপান্তর তৈরি করুন: এ-> সর্বশেষ -> ভি, বি-> সর্বশেষ -> ভি, সি-> শেষ -> ভি,
    • আপনার কাছ থেকে আপনি যে কোনও ব্লকে যেতে পারেন

সমস্ত রেজপ্লেক্স অপারেটরকে এভাবে রূপান্তর করা যায়। শুধু চেষ্টা করুন *

শেষ অংশটি রেজিএক্সপ্সকে পার্স করা যার জন্য খুব সাধারণ ব্যাকরণের প্রয়োজন:

 or: seq ('|' seq)*
 seq: empty
 seq: atom seq
 seq: paran seq
 paran: '(' or ')'

আশা করি একটি সাধারণ ব্যাকরণ বাস্তবায়ন করা হয়েছে (আমি মনে করি এলএল (1), তবে আমি ভুল হলে আমাকে সংশোধন করুন) এনএফএ তৈরির চেয়ে অনেক সহজ।

আপনার একবার এনএফএ হয়ে গেলে আপনি টার্মিনাল নোড না পৌঁছা পর্যন্ত ব্যাকট্র্যাক করতে হবে।

উত্স কোড (বা এখানে ):

from functools import *

WORDCHAR = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_'


def match_nothing(txt, pos):
  return True, pos

def match_character(c, txt, pos):
  return pos < len(txt) and txt[pos] == c, pos + 1

def match_space(txt, pos):
  return pos < len(txt) and txt[pos].isspace(), pos + 1

def match_word(txt, pos):
  return pos < len(txt) and txt[pos] in WORDCHAR, pos + 1

def match_nonword(txt, pos):
  return pos < len(txt) and txt[pos] not in WORDCHAR, pos + 1

def match_dot(txt, pos):
  return pos < len(txt), pos + 1

def match_start(txt, pos):
  return pos == 0, pos

def match_end(txt, pos):
  return pos == len(txt), pos


def create_state(states, match=None, last=None, next=None, name=None):
  if next is None: next = []
  if match is None: match = match_nothing

  state = len(states)
  states[state] = (match, next, name)
  if last is not None:
    states[last][1].append(state)

  return state


def compile_or(states, last, regexp, pos):
  mfirst = create_state(states, last=last, name='or_first')
  mlast = create_state(states, name='or_last')

  while True:
    pos, first, last = compile_seq(states, mfirst, regexp, pos)
    states[last][1].append(mlast)
    if pos != len(regexp) and regexp[pos] == '|':
      pos += 1
    else:
      assert pos == len(regexp) or regexp[pos] == ')'
      break

  return pos, mfirst, mlast


def compile_paren(states, last, regexp, pos):
  states.setdefault(-2, [])   # stores indexes
  states.setdefault(-1, [])   # stores text

  group = len(states[-1])
  states[-2].append(None)
  states[-1].append(None)

  def match_pfirst(txt, pos):
    states[-2][group] = pos
    return True, pos

  def match_plast(txt, pos):
    old = states[-2][group]
    states[-1][group] = txt[old:pos]
    return True, pos

  mfirst = create_state(states, match=match_pfirst, last=last, name='paren_first')
  mlast = create_state(states, match=match_plast, name='paren_last')

  pos, first, last = compile_or(states, mfirst, regexp, pos)
  assert regexp[pos] == ')'

  states[last][1].append(mlast)
  return pos + 1, mfirst, mlast


def compile_seq(states, last, regexp, pos):
  first = create_state(states, last=last, name='seq')
  last = first

  while pos < len(regexp):
    p = regexp[pos]
    if p == '\\':
      pos += 1
      p += regexp[pos]

    if p in '|)':
      break

    elif p == '(':
      pos, first, last = compile_paren(states, last, regexp, pos + 1)

    elif p in '+*':
      # first -> u ->...-> last -> v -> t
      # v -> first (matches at least once)
      # first -> t (skip on *)
      # u becomes new first
      # first is inserted before u

      u = create_state(states)
      v = create_state(states, next=[first])
      t = create_state(states, last=v)

      states[last][1].append(v)
      states[u] = states[first]
      states[first] = (match_nothing, [[u], [u, t]][p == '*'])

      last = t
      pos += 1

    else:  # simple states
      if p == '^':
    state = create_state(states, match=match_start, last=last, name='begin')
      elif p == '$':
    state = create_state(states, match=match_end, last=last, name='end')
      elif p == '.':
    state = create_state(states, match=match_dot, last=last, name='dot')
      elif p == '\\.':
    state = create_state(states, match=partial(match_character, '.'), last=last, name='dot')
      elif p == '\\s':
    state = create_state(states, match=match_space, last=last, name='space')
      elif p == '\\w':
    state = create_state(states, match=match_word, last=last, name='word')
      elif p == '\\W':
    state = create_state(states, match=match_nonword, last=last, name='nonword')
      elif p.isalnum() or p in '_@':
    state = create_state(states, match=partial(match_character, p), last=last, name='char_' + p)
      else:
    assert False

      first, last = state, state
      pos += 1

  return pos, first, last


def compile(regexp):
  states = {}
  pos, first, last = compile_or(states, create_state(states, name='root'), regexp, 0)
  assert pos == len(regexp)
  return states, last


def backtrack(states, last, string, start=None):
  if start is None:
    for i in range(len(string)):
      if backtrack(states, last, string, i):
    return True
    return False

  stack = [[0, 0, start]]   # state, pos in next, pos in text
  while stack:
    state = stack[-1][0]
    pos = stack[-1][2]
    #print 'in state', state, states[state]

    if state == last:
      print 'Matches: ', string[start:pos]
      for i in xrange(len(states[-1])):
    print 'Group', i + 1, states[-1][i]
      return True

    while stack[-1][1] < len(states[state][1]):
      nstate = states[state][1][stack[-1][1]]
      stack[-1][1] += 1

      ok, npos = states[nstate][0](string, pos)
      if ok:
    stack.append([nstate, 0, npos])
    break
      else:
    pass
    #print 'not matched', states[nstate][2]
    else:
      stack.pop()

  return False



# regexp = '(\\w+)@(\\w+)(\\.com|\\.net)'
# string = 'sam@test.net'
regexp = raw_input()
string = raw_input()

states, last = compile(regexp)
backtrack(states, last, string)

1
+1 বাহ ... আমি পিএইচপি দিয়ে নিজে এটি করার চেষ্টা করেছি এবং সম্পূর্ণ ব্যর্থ হয়েছি।
নাথান ওসমান

টিআইএল (a+b)+ম্যাচ করে abaabaaabaaaab
আলেকজান্দ্রু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.