سؤال

سأقوم بتنفيذ أداة رمزية في بايثون وكنت أتساءل عما إذا كان بإمكانك تقديم بعض النصائح حول الأسلوب؟

لقد قمت بتطبيق رمز مميز من قبل في لغة C وفي Java، لذا فأنا موافق على النظرية، وأود فقط التأكد من أنني أتبع أنماط لغة بايثون وأفضل الممارسات.

أنواع الرموز المميزة للإدراج:

في Java، على سبيل المثال، سيكون لدي قائمة بالحقول كما يلي:

public static final int TOKEN_INTEGER = 0

لكن من الواضح أنه لا توجد طريقة (على ما أعتقد) للإعلان عن متغير ثابت في بايثون، لذا يمكنني فقط استبدال ذلك بإعلانات متغيرات عادية ولكن هذا لا يبدو لي كحل رائع حيث يمكن تغيير الإعلانات.

إرجاع الرموز المميزة من Tokenizer:

هل هناك بديل أفضل لمجرد إرجاع قائمة من الصفوف على سبيل المثال؟

[ (TOKEN_INTEGER, 17), (TOKEN_STRING, "Sixteen")]?

هتافات،

بيت

هل كانت مفيدة؟

المحلول

وبيثون نهجا "نحن جميعا البالغين بالتراضي" لإخفاء المعلومات. لا بأس من استخدام المتغيرات كما لو كانت الثوابت، والثقة التي سيكون للمستخدمين من التعليمات البرمجية الخاصة بك لا تفعل شيئا غبيا.

نصائح أخرى

وهناك فئة لا يحملون وثائق في وحدة re دعا re.Scanner. انها واضحة جدا للاستخدام لtokenizer:

import re
scanner=re.Scanner([
  (r"[0-9]+",       lambda scanner,token:("INTEGER", token)),
  (r"[a-z_]+",      lambda scanner,token:("IDENTIFIER", token)),
  (r"[,.]+",        lambda scanner,token:("PUNCTUATION", token)),
  (r"\s+", None), # None == skip token.
])

results, remainder=scanner.scan("45 pigeons, 23 cows, 11 spiders.")
print results

وسيؤدي

[('INTEGER', '45'),
 ('IDENTIFIER', 'pigeons'),
 ('PUNCTUATION', ','),
 ('INTEGER', '23'),
 ('IDENTIFIER', 'cows'),
 ('PUNCTUATION', ','),
 ('INTEGER', '11'),
 ('IDENTIFIER', 'spiders'),
 ('PUNCTUATION', '.')]

واعتدت re.Scanner لكتابة التكوين أنيق جدا / منظم تنسيق البيانات محلل في سوى بضع مئات من الخطوط.

في كثير من الحالات، إكسب. عند تحليل المدخلات طويلة تيارات، قد تجد أنه أكثر فائدة لتنفيذ لكم tokenizer بوصفها وظيفة المولد. وبهذه الطريقة يمكنك تكرار بسهولة على كل الرموز دون الحاجة إلى الكثير من الذاكرة لبناء قائمة من الرموز أولا.

لمولد رؤية الاقتراح الأصلي أو غيرها من المستندات عبر الإنترنت

وشكرا لمساعدتكم، لقد بدأت لتحقيق هذه الأفكار معا، وجئت مع التالية. هل هناك أى خطأ فادحا مع هذا التطبيق (وخاصة انا قلق حول تمرير كائن الملف إلى tokenizer):

class Tokenizer(object):

  def __init__(self,file):
     self.file = file

  def __get_next_character(self):
      return self.file.read(1)

  def __peek_next_character(self):
      character = self.file.read(1)
      self.file.seek(self.file.tell()-1,0)
      return character

  def __read_number(self):
      value = ""
      while self.__peek_next_character().isdigit():
          value += self.__get_next_character()
      return value

  def next_token(self):
      character = self.__peek_next_character()

      if character.isdigit():
          return self.__read_number()

و"هل هناك بديل أفضل ببساطة لمجرد العودة قائمة الصفوف؟"

وكلا. أنه يعمل بشكل جيد حقا.

و"هل هناك بديل أفضل ببساطة لمجرد العودة قائمة الصفوف؟"

وهذا هو النهج المتبع من قبل وحدة "tokenize" لتحليل شفرة المصدر بيثون. يمكن إرجاع قائمة بسيطة من المجموعات تعمل بشكل جيد جدا.

ولقد بنيت مؤخرا tokenizer، أيضا، ومرت من خلال بعض القضايا الخاصة بك.

وأعلن

ورمز أنواع باسم "الثوابت"، أي المتغيرات مع أسماء ALL_CAPS، على مستوى وحدة. على سبيل المثال،

_INTEGER = 0x0007
_FLOAT = 0x0008
_VARIABLE = 0x0009

ووهلم جرا. ولقد استخدمت تسطير أمام اسم الإشارة إلى أن بطريقة ما تلك الحقول "خاصة" للوحدة، ولكن في الحقيقة أنا لا أعرف إذا كان هذا هو الوضع الطبيعي أو المستحسن، ولا حتى مقدار Pythonic. (أيضا، أنا ربما خندق الأرقام في صالح الجمل، لأنه خلال التصحيح هم أكثر قابلية للقراءة الكثير).

ويتم إرجاع الرموز كما الصفوف اسمه.

from collections import namedtuple
Token = namedtuple('Token', ['value', 'type'])
# so that e.g. somewhere in a function/method I can write...
t = Token(n, _INTEGER)
# ...and return it properly

ولقد استخدمت الصفوف اسمه بسبب كود العميل tokenizer ل(مثل محلل) يبدو أكثر وضوحا قليلا أثناء استخدام أسماء (على سبيل المثال token.value) بدلا من الأرقام القياسية (مثل رمز [0]).

وأخيرا، لقد لاحظت أنه في بعض الأحيان، وخاصة كتابة الاختبارات، وأنا أفضل أن تمرير السلسلة إلى tokenizer بدلا من كائن الملف. أنا أسميها "القارئ"، ولها طريقة محددة لفتحه والسماح بالوصول tokenizer من خلال واجهة واحدة.

def open_reader(self, source):
    """
    Produces a file object from source.
    The source can be either a file object already, or a string.
    """
    if hasattr(source, 'read'):
        return source
    else:
        from io import StringIO
        return StringIO(source)

وعندما أبدأ شيئا جديدا في بيثون وعادة ما ننظر أولا في بعض وحدات أو مكتبات للاستخدام. هناك 90٪ + فرصة أن هناك بالفعل سومثينغ المتاحة.

لtokenizers وموزعي وهذا هو بالتأكيد لذلك. هل نظرت في PyParsing ؟

لقد قمت بتطبيق رمز مميز للغة برمجة تشبه لغة C.ما فعلته هو تقسيم إنشاء الرموز إلى طبقتين:

  • أ الماسح الضوئي السطحي:يقرأ هذا النص فعليًا ويستخدم التعبير العادي لتقسيمه إلى الرموز الأكثر بدائية فقط (العوامل، والمعرفات، والأرقام، ...)؛ينتج عن هذا صفوف (الاسم المميز، السلسلة الممسوحة ضوئيًا، نقطة البدء، نقطة النهاية).
  • أ رمز مميز:يؤدي هذا إلى استهلاك الصفوف من الطبقة الأولى، وتحويلها إلى كائنات رمزية (أعتقد أن الصفوف المسماة ستفعل ذلك أيضًا).والغرض منه هو اكتشاف بعض التبعيات طويلة المدى في تدفق الرمز المميز، وخاصة السلاسل (مع علامات الاقتباس الافتتاحية والختامية) والتعليقات (مع المعاجم الافتتاحية الخاصة بها؛- نعم، أردت الاحتفاظ بالتعليقات!) وإجبارها على رموز فردية.يتم بعد ذلك إرجاع الدفق الناتج من كائنات الرمز المميز إلى محلل مستهلك.

كلاهما مولدات.وكانت فوائد هذا النهج:

  • تتم قراءة النص الخام فقط بالطريقة الأكثر بدائية، مع تعبيرات عادية بسيطة - سريعة ونظيفة.
  • تم بالفعل تنفيذ الطبقة الثانية كمحلل بدائي لاكتشاف القيم الحرفية للسلسلة والتعليقات - إعادة استخدام تقنية المحلل اللغوي.
  • لا يتعين عليك إجهاد الماسح الضوئي السطحي بالاكتشافات المعقدة.
  • لكن المحلل الحقيقي يحصل على رموز على المستوى الدلالي للغة المراد تحليلها (سلاسل، تعليقات مرة أخرى).

أشعر بسعادة غامرة بهذا النهج متعدد الطبقات.

وكنت أنتقل إلى ممتاز <م> تجهيز النصوص في بيثون من جانب ديفيد ميرتز

وهذا يجري في وقت متأخر الجواب، وهناك الآن شيء في الوثائق الرسمية: <لأ href = "http://docs.python.org/3.2/library/re.html#writing-a-tokenizer" يختلط = " نوفولو "> كتابة tokenizer مع مكتبة القياسية re. هذا المحتوى في وثائق بيثون 3 غير موجود في مستندات السنة التحضيرية 2.7. لكنه لا يزال ينطبق على الثعابين القديمة.

وهذا يشمل كلا من حروف قلة، سهلة الإعداد، والكتابة مولد عن العديد من الإجابات هنا والمقترحة.

إذا المستندات ليست Pythonic، وأنا لا أعرف ما هو: -)

و"هل هناك بديل أفضل ببساطة لمجرد العودة قائمة الصفوف"

وكان لي لتنفيذ tokenizer، ولكنها تتطلب نهجا أكثر تعقيدا من قائمة الصفوف، ولذلك فإنني تنفيذها فئة لكل رمز. يمكنك ثم إرجاع قائمة من الحالات الطبقة، أو إذا كنت ترغب في حفظ الموارد، يمكنك العودة شيئا تنفيذ واجهة مكرر وتوليد رمز المقبل في حين تقدم لك في التوزيع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top