أخطاء مخصصة ل RegexParsers

قد يساعدني أحدهم في فهم السلوك التالي: parseAll (parseIf، "If bla blablaa") يجب أن يؤدي إلى المتوقع . بدلاً من ذلك ، أحصل دائمًا على string align regex 'is \ b' expected ولكن 'b' found . أعتقد أن لها علاقة بالفضاء لأن "إذا كانت bla blablaa" (لاحظ المسافات البيضاء في البداية) ينتج عنها نفس السلوك. لقد حاولت ذلك مع StandardTokenParsers وكل شيء سار على ما يرام. لكن STP للأسف لا يدعم التعبير العادي. سؤال المتابعة: كيف يمكنني تغيير RegexParsers بحيث يستخدم تسلسل سلاسل بدلاً من تسلسل أحرف؟ وهذا من شأنه أن يجعل الإبلاغ عن الأخطاء أكثر سهولة.

lazy val parseIf = roleGiverIf ~ giverRole

lazy val roleGiverIf =
  kwIf ~> identifier | failure("""A rule must begin with if""")
lazy val giverRole =
  kwIs ~> identifier | failure("""is expected""")

lazy val keyword =
  kwIf | kwAnd | kwThen | kwOf | kwIs | kwFrom | kwTo

lazy val identifier =
  not(keyword) ~ roleEntityLiteral
// ...

def roleEntityLiteral: Parser[String] =
  """([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})\S*""".r 
def kwIf: Parser[String] = "If\\b".r
def kwIs: Parser[String] = "is\\b".r

// ...

parseAll(parseIf, "If bla blablaa") match {
  case Success(parseIf, _) => println(parseIf)
  case Failure(msg, _) => println("Failure: " + msg)
  case Error(msg, _) => println("Error: " + msg)
1

1 إجابة

هذه المشكلة غريبة جدا. عند الاتصال | ويكون كلا الجانبين من الفشل ، يتم تحديد الجانب الذي حدث فيه الفشل آخر ، مع ارتباطات لصالح الجانب الأيسر.

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

والسبب خفي إلى حد ما - لم أجده إلا من خلال عبارات sprinkling log على جميع موزعي. لفهمه ، يجب أن تفهم كيف يتخطى RegexParser المسافات . على وجه الخصوص ، يتم تخطي المساحات على قبول . لأن فشل لا يستدعي قبول ، فإنه لا يتخطى المسافات.

في حين أن فشل kwIs يحدث على b ، كالمساحة كما تم تخطيها ، فإن فشل فشل يحدث على المساحة بعد > إذا </القانون> </م>. هنا:

If bla blablaa
   ^ kwIs fails here
  ^ failure fails here

لذلك ، يحصل على رسالة الخطأ على kwIs الأسبقية بالقاعدة التي ذكرتها.

يمكنك التغلب على هذه المشكلة عن طريق جعل المحلل اللغوي يتخطى المسافات دون مطابقة أي شيء. من المهم أن يتطابق هذا النمط دائمًا ، أو ستتلقى رسالة خطأ أكثر إرباكًا. هذا اقتراح أعتقد أنه يعمل:

"\\b|$".r ~ failure("is expected")

الحل الآخر هو استخدام acceptIf أو acceptMatch بدلاً من استخدام regex الضمني ، وفي هذه الحالة يمكنك تقديم رسالة خطأ مخصصة.

0
وأضاف
awertos وأخيرا وجدت ما كانت المشكلة. كان الحل الأول أكثر ملاءمة مما كنت أعتقد - أنا فقط غيرته لجعل الخطأ يظهر في المكان المناسب ، من خلال عدم استهلاك أي أحرف غير ذات مساحة.
وأضاف المؤلف Daniel C. Sobral, مصدر
لقد كتبت محلل مع regex والمقدرة lexical واستخدمت acceptIf كما تقترح. ولكن لا يزال من الغريب أن المثال أعلاه لن يعمل كما هو متوقع. شكرا لمساعدتك
وأضاف المؤلف awertos, مصدر