JavaRush /وبلاگ جاوا /Random-FA /عبارات منظم در جاوا، قسمت 5

عبارات منظم در جاوا، قسمت 5

در گروه منتشر شد
ترجمه‌ای از راهنمای کوتاه عبارات منظم در جاوا را که توسط جف فریسن برای وب‌سایت javaworld نوشته شده است، در اختیار شما قرار می‌دهیم. برای سهولت در مطالعه مقاله را به چند قسمت تقسیم کرده ایم. این قسمت قسمت پایانی است. عبارات منظم در جاوا، قسمت 5 - 1عبارات با قاعده در جاوا، قسمت 1 عبارات با قاعده در جاوا، قسمت 2 عبارات با قاعده در جاوا، قسمت 3 عبارات با قاعده در جاوا، قسمت 4

استفاده از عبارات منظم برای تحلیل واژگانی

یکی از کاربردهای مفیدتر عبارات منظم، کتابخانه ای از کدهای قابل استفاده مجدد برای انجام تحلیل واژگانی است که جزء کلیدی هر کامپایلر یا اسمبلر است. در این مورد، جریان ورودی کاراکترها به یک جریان خروجی از نشانه‌ها گروه‌بندی می‌شود - نام‌هایی برای دنباله‌هایی از کاراکترها که معنای مشترکی دارند. به عنوان مثال، با مواجهه با دنباله کاراکترهای c, o, u, n, t, e, rدر جریان ورودی، تحلیلگر واژگانی می تواند یک نشانه ID(شناسه) را خروجی دهد. دنباله نویسه های متناظر با نشانه، واژگان نامیده می شود.
بیشتر در مورد نشانگرها و واژگان
توکن هایی مانند ID می توانند با بسیاری از توالی کاراکتر مطابقت داشته باشند. در مورد چنین نشانه هایی، رمز واقعی مربوط به توکن نیز توسط کامپایلر، اسمبلر یا سایر ابزارهایی که نیاز به تحلیل واژگانی دارد مورد نیاز است. برای نشانه‌هایی که نشان‌دهنده یک دنباله خاص از کاراکترها هستند، مانند نشانه‌ای که PLUSفقط با کاراکتر مطابقت دارد +، نشانه واقعی مورد نیاز نیست زیرا می‌توان آن را از روی نشانه شناسایی کرد.
عبارات منظم بسیار کارآمدتر از تحلیلگرهای واژگانی مبتنی بر حالت هستند، که باید با دست نوشته شوند و به طور کلی نمی توان آنها را دوباره استفاده کرد. نمونه‌ای از یک تحلیل‌گر واژگانی مبتنی بر عبارت منظم، JLex است ، یک مولد واژگانی برای زبان جاوا که از عبارات منظم برای تعریف قوانین برای تجزیه یک جریان داده ورودی به نشانه‌ها استفاده می‌کند. مثال دیگر Lexan است.

آشنایی با لکسان

Lexan یک کتابخانه جاوا قابل استفاده مجدد برای تحلیل واژگانی است. این بر اساس کد از مجموعه پست وبلاگ Writing a Parser in Java در وب سایت Cogito Learning است . این کتابخانه از کلاس های زیر تشکیل شده است که در بسته ca.javajeff.lexanموجود در کد قابل دانلود این مقاله موجود است:
  • Lexan: تحلیلگر واژگانی;
  • LexanException: استثنا پرتاب شده در سازنده کلاسLexan;
  • LexException: در صورت تشخیص نحو نادرست در طول تجزیه و تحلیل واژگانی، استثنا پرتاب می شود.
  • Token: نام با ویژگی عبارت منظم.
  • TokLex: جفت توکن/ژتون.
سازنده Lexan(java.lang.Class tokensClass)یک تحلیلگر واژگانی جدید ایجاد می کند. به یک آرگومان در قالب یک شی کلاس java.lang.Classمطابق با کلاس ثابت نوع نیاز دارد static Token. با استفاده از Reflection API، سازنده تمام ثابت ها را Tokenدر آرایه ای از مقادیر می خواند Token[]. اگر Tokenهیچ ثابتی وجود نداشته باشد، یک استثنا پرتاب می شود LexanException. عبارات منظم در جاوا، قسمت 5 - 2کلاس Lexanهمچنین دو روش زیر را ارائه می دهد:
  • متد لیستی از این lexer را برمی گرداند.List getTokLexes() Token
  • Метод void lex(String str)آنالیز واژگانی رشته ورودی [با قرار دادن نتیجه] را در لیستی از مقادیر از نوع انجام می دهد TokLex. اگر با کاراکتری مواجه شوید که با هیچ یک از الگوهای آرایه مطابقت نداشته باشد Token[]، یک استثنا ایجاد می شود LexException.
کلاس LexanExceptionهیچ متدی ندارد؛ از یک متد ارثی برای برگرداندن یک پیام استثنا استفاده می کند getMessage(). در مقابل، کلاس LexExceptionمتدهای زیر را ارائه می دهد:
  • این روش int getBadCharIndex()موقعیت یک کاراکتر را برمی‌گرداند که با هیچ یک از الگوهای نشانگر مطابقت ندارد.
  • این روش String getText()متنی را که در هنگام ایجاد استثنا مورد تجزیه و تحلیل قرار گرفته بود، برمی گرداند.
کلاس برای برگرداندن نام نشانگر Tokenمتد را لغو می کند . toString()همچنین روشی را ارائه می دهد String getPattern()که ویژگی عبارت منظم توکن را برمی گرداند. کلاس TokLexمتدی را ارائه می دهد Token getToken()که توکن خود را برمی گرداند. همچنین روشی را ارائه می دهد String getLexeme()که توکن خود را برمی گرداند.

نمایش کتابخانه لکسان

برای نشان دادن نحوه عملکرد کتابخانه، Lexanیک برنامه کاربردی نوشتم LexanDemo. این شامل کلاس های LexanDemo, BinTokensو MathTokens. NoTokensکد منبع برنامه LexanDemoدر فهرست 2 نشان داده شده است. فهرست 2. نمایش کتابخانه Lexan در عمل
import ca.javajeff.lexan.Lexan;
import ca.javajeff.lexan.LexanException;
import ca.javajeff.lexan.LexException;
import ca.javajeff.lexan.TokLex;

public final class LexanDemo
{
   public static void main(String[] args)
   {
      lex(MathTokens.class, " sin(x) * (1 + var_12) ");
      lex(BinTokens.class, " 1 0 1 0 1");
      lex(BinTokens.class, "110");
      lex(BinTokens.class, "1 20");
      lex(NoTokens.class, "");
   }

   private static void lex(Class tokensClass, String text)
   {
      try
      {
         Lexan lexan = new Lexan(tokensClass);
         lexan.lex(text);
         for (TokLex tokLex: lexan.getTokLexes())
            System.out.printf("%s: %s%n", tokLex.getToken(),
                              tokLex.getLexeme());
      }
      catch (LexanException le)
      {
         System.err.println(le.getMessage());
      }
      catch (LexException le)
      {
         System.err.println(le.getText());
         for (int i = 0; i < le.getBadCharIndex(); i++)
            System.err.print("-");
         System.err.println("^");
         System.err.println(le.getMessage());
      }
      System.out.println();
   }
}
روش main()فهرست 2 یک ابزار lex()برای نشان دادن تحلیل واژگانی با استفاده از Lexan فراخوانی می کند. هر فراخوانی به این متد از کلاس نشانه‌های موجود در شی Classو رشته برای تجزیه ارسال می‌شود. متد lex()ابتدا یک شی از کلاس را Lexanبا ارسال شی Classبه سازنده کلاس ایجاد می کند Lexan. lex()و سپس متد کلاس را در آن رشته فراخوانی می کند Lexan. اگر تحلیل واژگانی موفقیت آمیز باشد، متد کلاس برای برگرداندن لیستی از اشیا TokLexفراخوانی می شود . برای هر یک از این اشیاء، متد کلاس آن برای برگرداندن توکن و متد کلاس آن برای برگرداندن نشانه فراخوانی می شود. هر دو مقدار در خروجی استاندارد چاپ می شوند. اگر تحلیل واژگانی با شکست مواجه شود، یکی از استثنائات پرتاب می شود و بر اساس آن رسیدگی می شود . برای اختصار، اجازه دهید فقط کلاسی را که این برنامه را تشکیل می دهد در نظر بگیریم . لیست 3 کد منبع آن را نشان می دهد. فهرست 3. شرح مجموعه ای از نشانه ها برای یک زبان ریاضی کوچکgetTokLexes()LexangetToken()TokLexgetLexeme()LexanExceptionLexExceptionMathTokens
import ca.javajeff.lexan.Token;

public final class MathTokens
{
   public final static Token FUNC = new Token("FUNC", "sin|cos|exp|ln|sqrt");
   public final static Token LPAREN = new Token("LPAREN", "\\(");
   public final static Token RPAREN = new Token("RPAREN", "\\)");
   public final static Token PLUSMIN = new Token("PLUSMIN", "[+-]");
   public final static Token TIMESDIV = new Token("TIMESDIV", "[*/]");
   public final static Token CARET = new Token("CARET", "\\^");
   public final static Token INTEGER = new Token("INTEGER", "[0-9]+");
   public final static Token ID = new Token("ID", "[a-zA-Z][a-zA-Z0-9_]*");
}
فهرست 3 نشان می دهد که کلاس MathTokensدنباله ای از ثابت های نوع را توصیف می کند Token. به هر یک از آنها مقدار یک شی اختصاص داده شده است Token. سازنده برای این شی، رشته ای را دریافت می کند که نام نشانگر است، همراه با یک عبارت منظم که تمام رشته های کاراکتر مرتبط با آن نشانگر را توصیف می کند. برای وضوح، مطلوب است که نام رشته نشانگر با نام ثابت یکی باشد، اما این مورد نیاز نیست. عبارات منظم در جاوا، قسمت 5 - 3موقعیت ثابت Tokenدر لیست نشانگرها مهم است. ثابت هایی که در بالاترین لیست قرار دارند، Tokenنسبت به مواردی که در زیر قرار دارند، اولویت دارند. به عنوان مثال، هنگام مواجه شدن با ، Lexan به جای sinعلامت، توکن را انتخاب می کند . اگر نشانگر قبل از نشانگر بود ، انتخاب می شد. FUNCIDIDFUNC

کامپایل و اجرای برنامه LexanDemo

کد قابل دانلود این مقاله شامل یک آرشیو lexan.zipحاوی تمام فایل های توزیع Lexan است. این بایگانی را باز کنید و به یک زیر شاخه demosاز فهرست اصلی بروید lexan. اگر از ویندوز استفاده می کنید، دستور زیر را برای کامپایل فایل های کد منبع برنامه آزمایشی اجرا کنید:
javac -cp ..\library\lexan.jar *.java
در صورت موفقیت آمیز بودن کامپایل، دستور زیر را برای اجرای برنامه دمو اجرا کنید:
java -cp ..\library\lexan.jar;. LexanDemo
شما باید نتایج زیر را ببینید:
FUNC: sin
LPAREN: (
ID: x
RPAREN: )
TIMESDIV: *
LPAREN: (
INTEGER: 1
PLUSMIN: +
ID: var_12
RPAREN: )
ONE: 1
ZERO: 0
ONE: 1
ZERO: 0
ONE: 1
ONE: 1
ONE: 1
ZERO: 0
1 20
--^
Неожиданный символ во входном тексте: 20
پیام Неожиданный символ во входном тексте: 20در نتیجه یک استثنا ایجاد می شود LexanExceptionکه دلیل آن این است که کلاس ثابتی را با مقداری به عنوان یک عبارت منظم BinTokensاعلام نمی کند . توجه داشته باشید که کنترل کننده استثنا موقعیت نویسه نامناسب به دست آمده از تحلیل واژگانی متن را خروجی می دهد. پیام از دست رفته نشانه ها نتیجه یک استثنا است که در کلاس اعلان نشده است . Token2LexExceptionNoTokensToken

پشت صحنه

Lexanاز کلاس Lexan به عنوان موتور خود استفاده می کند. به اجرای این کلاس در لیست 4 نگاهی بیندازید و به سهم عبارات منظم در قابل استفاده مجدد موتور توجه کنید. فهرست 4. ایجاد معماری تحلیلگر واژگانی بر اساس عبارات منظم
package ca.javajeff.lexan;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;

/**
 *  Лексический анализатор. Этот класс можно использовать для
 *  преобразования входного потока символов в выходной поток маркеров.
 *
 *  @Author Джефф Фризен
 */

public final class Lexan
{
   private List tokLexes;

   private Token[] values;

   /**
    *  Инициализируем лексический анализатор набором an objectов Token.
    *
    *  @параметры tokensClass – an object Class класса, содержащего
    *       набор an objectов Token
    *
    *  @генерирует исключение LexanException в случае невозможности
    *       формирования an object Lexan, возможно, из-за отсутствия an objectов
    *       Token в классе
    */

   public Lexan(Class tokensClass) throws LexanException
   {
      try
      {
         tokLexes = new ArrayList<>();
         List _values = new ArrayList<>();
         Field[] fields = tokensClass.getDeclaredFields();
         for (Field field: fields)
            if (field.getType().getName().equals("ca.javajeff.lexan.Token"))
               _values.add((Token) field.get(null));
         values = _values.toArray(new Token[0]);
         if (values.length == 0)
            throw new LexanException("маркеры отсутствуют");
      }
      catch (IllegalAccessException iae)
      {
         throw new LexanException(iae.getMessage());
      }

   /**
    * Получаем список TokLex'ов этого лексического анализатора.
    *
    *  @возвращает список TokLex'ов
    */

   public List getTokLexes()
   {
      return tokLexes;
   }

   /** * Выполняет лексический анализ входной строки [с помещением * результата] в список TokLex'ов. * * @параметры str – строка, подвергаемая лексическому анализу * * @генерирует исключение LexException: во входных данных обнаружен * неожиданный символ */

   public void lex(String str) throws LexException
   {
      String s = new String(str).trim(); // удалить ведущие пробелы
      int index = (str.length() - s.length());
      tokLexes.clear();
      while (!s.equals(""))
      {
         boolean match = false;
         for (int i = 0; i < values.length; i++)
         {
            Token token = values[i];
            Matcher m = token.getPattern().matcher(s);
            if (m.find())
            {
               match = true;
               tokLexes.add(new TokLex(token, m.group().trim()));
               String t = s;
               s = m.replaceFirst("").trim(); // удалить ведущие пробелы
               index += (t.length() - s.length());
               break;
            }
         }
         if (!match)
            throw new LexException("Неожиданный символ во входном тексте: "
                                    + s, str, index);
      }
   }
}
کد روش lex()بر اساس کد ارائه شده در پست وبلاگ "Writing a Parser in Java: A Token Generator" در وب سایت Cogito Learning است. این پست را بخوانید تا درباره نحوه استفاده Lexan از Regex API برای کامپایل کد بیشتر بدانید. عبارات منظم در جاوا، قسمت 5 - 4

نتیجه

عبارات منظم ابزار مفیدی است که می تواند برای هر توسعه دهنده ای مفید باشد. Regex API زبان برنامه نویسی جاوا استفاده از آنها را در برنامه ها و کتابخانه ها آسان می کند. اکنون که درک اولیه ای از عبارات منظم و این API دارید، نگاهی به مستندات SDK بیندازید java.util.regexتا حتی بیشتر در مورد عبارات منظم و روش های Regex API اضافی بیاموزید.
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION