JavaRush /Blog Java /Random-MS /Ungkapan Biasa di Jawa, Bahagian 5

Ungkapan Biasa di Jawa, Bahagian 5

Diterbitkan dalam kumpulan
Kami menyampaikan kepada perhatian anda terjemahan panduan ringkas kepada ungkapan biasa dalam Java, yang ditulis oleh Jeff Friesen untuk laman web javaworld. Untuk memudahkan pembacaan, kami telah membahagikan artikel tersebut kepada beberapa bahagian. Bahagian ini adalah yang terakhir. Ungkapan Biasa dalam Java, Bahagian 5 - 1Ungkapan Biasa dalam Jawa, Ungkapan Biasa Bahagian 1 dalam Jawa, Ungkapan Biasa Bahagian 2 dalam Jawa, Ungkapan Biasa Bahagian 3 dalam Jawa, Bahagian 4

Menggunakan ungkapan biasa untuk analisis leksikal

Aplikasi ungkapan biasa yang lebih berguna ialah perpustakaan kod boleh guna semula untuk melaksanakan analisis leksikal, komponen utama mana-mana pengkompil atau penghimpun. Dalam kes ini, aliran input aksara dikumpulkan ke dalam aliran keluaran token - nama untuk jujukan aksara yang mempunyai maksud yang sama. Sebagai contoh, setelah menemui urutan aksara c, o, u, n, t, e, r, dalam aliran input, penganalisis leksikal boleh mengeluarkan token ID(pengecam). Urutan aksara yang sepadan dengan token dipanggil leksem.
Lebih lanjut mengenai penanda dan leksem
Token seperti ID boleh memadankan banyak jujukan aksara. Dalam kes token tersebut, token sebenar yang sepadan dengan token juga diperlukan oleh pengkompil, penghimpun atau utiliti lain yang memerlukan analisis leksikal. Untuk token yang mewakili satu jujukan aksara tertentu, seperti token PLUSyang sepadan hanya dengan watak +, token sebenar tidak diperlukan kerana ia boleh [unik] ditentukan oleh token.
Ungkapan biasa jauh lebih cekap daripada penganalisis leksikal berasaskan negeri, yang mesti ditulis dengan tangan dan secara amnya tidak boleh digunakan semula. Contoh penganalisis leksikal berasaskan ungkapan biasa ialah JLex , penjana leksikal untuk bahasa Java yang menggunakan ungkapan biasa untuk mentakrifkan peraturan untuk memecahkan aliran data input kepada token. Contoh lain ialah Lexan.

Mengenali Lexan

Lexan ialah perpustakaan Java yang boleh digunakan semula untuk analisis leksikal. Ia berdasarkan kod daripada siri catatan blog Menulis Parser dalam Java di tapak web Pembelajaran Cogito . Pustaka terdiri daripada kelas berikut, yang terdapat dalam pakej ca.javajeff.lexanyang disertakan dalam kod yang boleh dimuat turun untuk artikel ini:
  • Lexan: penganalisis leksikal;
  • LexanException: pengecualian yang dilemparkan dalam pembina kelasLexan;
  • LexException: pengecualian dilemparkan jika sintaks yang salah dikesan semasa analisis leksikal;
  • Token: nama dengan atribut ungkapan biasa;
  • TokLex: pasangan token/token.
Pembina Lexan(java.lang.Class tokensClass)mencipta penganalisis leksikal baharu. Ia memerlukan satu hujah dalam bentuk objek kelas java.lang.Classyang sepadan dengan kelas pemalar jenis static Token. Menggunakan API Refleksi, pembina membaca semua pemalar Tokenke dalam tatasusunan nilai Token[]. Jika Tokentiada pemalar, pengecualian dilemparkan LexanException. Ungkapan Biasa dalam Java, Bahagian 5 - 2Kelas ini Lexanjuga menyediakan dua kaedah berikut:
  • Kaedah ini mengembalikan senarai lexer ini;List getTokLexes() Token
  • Метод void lex(String str)melakukan analisis leksikal rentetan input [dengan keputusan diletakkan] ke dalam senarai nilai jenis TokLex. Jika aksara ditemui yang tidak sepadan dengan mana - mana corak tatasusunan Token[], pengecualian akan dilemparkan LexException.
Kelas LexanExceptiontidak mempunyai kaedah; ia menggunakan kaedah yang diwarisi untuk mengembalikan mesej pengecualian getMessage(). Sebaliknya, kelas LexExceptionmenyediakan kaedah berikut:
  • Kaedah ini int getBadCharIndex()mengembalikan kedudukan watak yang tidak sepadan dengan mana-mana corak penanda.
  • Kaedah ini String getText()mengembalikan teks yang telah dianalisis apabila pengecualian dijana.
Kelas Tokenmengatasi kaedah toString()untuk mengembalikan nama penanda. Ia juga menyediakan kaedah String getPattern()yang mengembalikan atribut ungkapan biasa token. Kelas TokLexmenyediakan kaedah Token getToken()yang mengembalikan tokennya. Ia juga menyediakan kaedah String getLexeme()yang mengembalikan tokennya.

Demonstrasi perpustakaan Lexan

Untuk menunjukkan cara perpustakaan berfungsi, Lexansaya menulis aplikasi LexanDemo. Ia terdiri daripada kelas LexanDemo, BinTokens, MathTokensdan NoTokens. Kod sumber untuk aplikasi LexanDemoditunjukkan dalam Penyenaraian 2. Penyenaraian 2. Demonstrasi perpustakaan Lexan dalam tindakan
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();
   }
}
Kaedah main()dalam Penyenaraian 2 memanggil utiliti lex()untuk menunjukkan analisis leksikal menggunakan Lexan. Setiap panggilan kepada kaedah ini diluluskan kelas token dalam objek Classdan rentetan untuk dihuraikan. Kaedah lex()pertama mencipta objek kelas Lexandengan menghantar objek Classkepada pembina kelas Lexan. Dan kemudian ia memanggil kaedah lex()kelas Lexanpada rentetan itu. Jika analisis leksikal berjaya, kaedah kelas TokLexdipanggil untuk mengembalikan senarai objek . Untuk setiap objek ini, kaedah kelasnya dipanggil untuk mengembalikan token dan kaedah kelasnya untuk mengembalikan token. Kedua-dua nilai dicetak ke output standard. Jika analisis leksikal gagal, salah satu pengecualian atau dibuang dan dikendalikan dengan sewajarnya . Untuk ringkasnya, mari kita pertimbangkan hanya kelas yang membentuk aplikasi ini . Penyenaraian 3 menunjukkan kod sumbernya. Penyenaraian 3. Penerangan tentang set token untuk bahasa matematik yang kecilgetTokLexes()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_]*");
}
Penyenaraian 3 menunjukkan bahawa kelas MathTokensmenerangkan jujukan pemalar jenis Token. Setiap daripada mereka diberikan nilai objek Token. Pembina untuk objek ini menerima rentetan yang merupakan nama penanda, bersama-sama dengan ungkapan biasa yang menerangkan semua rentetan aksara yang dikaitkan dengan penanda itu. Untuk kejelasan, adalah wajar bahawa nama rentetan penanda adalah sama dengan nama pemalar, tetapi ini tidak diperlukan. Ungkapan Biasa dalam Java, Bahagian 5 - 3Kedudukan pemalar Tokendalam senarai penanda adalah penting. Pemalar yang terletak lebih tinggi dalam senarai Tokendiutamakan daripada yang terletak di bawah. Sebagai contoh, apabila menghadapi sin, Lexan memilih token FUNCdan bukannya ID. Jika penanda IDtelah mendahului penanda FUNC, ia akan dipilih.

Menyusun dan menjalankan aplikasi LexanDemo

Kod yang boleh dimuat turun untuk artikel ini termasuk arkib lexan.zipyang mengandungi semua fail pengedaran Lexan. Buka pembungkusan arkib ini dan pergi ke subdirektori demosdirektori akar lexan. Jika anda menggunakan Windows, jalankan arahan berikut untuk menyusun fail kod sumber aplikasi demo:
javac -cp ..\library\lexan.jar *.java
Jika kompilasi berjaya, jalankan arahan berikut untuk menjalankan aplikasi demo:
java -cp ..\library\lexan.jar;. LexanDemo
Anda sepatutnya melihat keputusan berikut:
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
Mesej Неожиданный символ во входном тексте: 20berlaku akibat pengecualian yang dilemparkan LexanExceptiondisebabkan oleh fakta bahawa kelas BinTokenstidak mengisytiharkan pemalar Tokendengan nilai 2sebagai ungkapan biasa. Ambil perhatian bahawa pengendali pengecualian mengeluarkan kedudukan watak yang tidak sesuai yang diperoleh daripada analisis leksikal teks. Mesej yang tiada token adalah hasil daripada pengecualian yang dilemparkan LexExceptionkerana NoTokenstiada pemalar diisytiharkan dalam kelas Token.

Disebalik tabir

Lexanmenggunakan kelas Lexan sebagai enjinnya. Lihatlah pelaksanaan kelas ini dalam Penyenaraian 4 dan perhatikan sumbangan ungkapan biasa untuk menjadikan enjin boleh digunakan semula. Penyenaraian 4. Mencipta seni bina penganalisis leksikal berdasarkan ungkapan biasa
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);
      }
   }
}
Kod kaedah lex()adalah berdasarkan kod yang disediakan dalam catatan blog "Menulis Parser dalam Java: Penjana Token" di laman web Cogito Learning. Baca siaran ini untuk mengetahui lebih lanjut tentang cara Lexan menggunakan API Regex untuk menyusun kod. Ungkapan Biasa di Jawa, Bahagian 5 - 4

Kesimpulan

Ungkapan biasa ialah alat berguna yang boleh berguna kepada mana-mana pembangun. Regex API bahasa pengaturcaraan Java menjadikannya mudah digunakan dalam aplikasi dan perpustakaan. Memandangkan anda sudah mempunyai pemahaman asas tentang ungkapan biasa dan API ini, lihat dokumentasi SDK java.util.regexuntuk mengetahui lebih lanjut tentang ungkapan biasa dan kaedah API Regex tambahan.
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION