JavaRush /Java Blog /Random-ID /Ekspresi Reguler di Java, Bagian 5

Ekspresi Reguler di Java, Bagian 5

Dipublikasikan di grup Random-ID
Untuk perhatian Anda, kami mempersembahkan terjemahan panduan singkat ekspresi reguler di Java, yang ditulis oleh Jeff Friesen untuk situs web javaworld. Untuk kemudahan membaca, kami telah membagi artikel menjadi beberapa bagian. Bagian ini adalah bagian terakhir. Ekspresi Reguler di Java, Bagian 5 - 1Ekspresi Reguler di Java, Bagian 1 Ekspresi Reguler di Java, Bagian 2 Ekspresi Reguler di Java, Bagian 3 Ekspresi Reguler di Java, Bagian 4

Menggunakan ekspresi reguler untuk analisis leksikal

Penerapan ekspresi reguler yang lebih berguna lagi adalah pustaka kode yang dapat digunakan kembali untuk melakukan analisis leksikal, yang merupakan komponen kunci dari setiap kompiler atau assembler. Dalam hal ini, aliran karakter masukan dikelompokkan ke dalam aliran token keluaran - nama untuk rangkaian karakter yang memiliki arti umum. Misalnya, setelah menemukan urutan karakter c, o, u, n, t, e, r, dalam aliran masukan, penganalisis leksikal dapat mengeluarkan token ID(pengidentifikasi). Urutan karakter yang bersesuaian dengan token disebut leksem.
Lebih lanjut tentang penanda dan leksem
Token seperti ID dapat mencocokkan banyak urutan karakter. Dalam kasus token seperti itu, token sebenarnya yang sesuai dengan token tersebut juga diperlukan oleh kompiler, assembler, atau utilitas lain yang memerlukan analisis leksikal. Untuk token yang mewakili satu rangkaian karakter tertentu, seperti token PLUSyang hanya bersesuaian dengan karakter tersebut +, token sebenarnya tidak diperlukan karena dapat ditentukan secara [secara unik] oleh token tersebut.
Ekspresi reguler jauh lebih efisien dibandingkan penganalisis leksikal berbasis negara, yang harus ditulis dengan tangan dan umumnya tidak dapat digunakan kembali. Contoh penganalisis leksikal berbasis ekspresi reguler adalah JLex , generator leksikal untuk bahasa Java yang menggunakan ekspresi reguler untuk menentukan aturan untuk memecah aliran data masukan menjadi token. Contoh lainnya adalah Lexan.

Mengenal Lexan

Lexan adalah perpustakaan Java yang dapat digunakan kembali untuk analisis leksikal. Hal ini didasarkan pada kode dari seri postingan blog Menulis Parser di Java di situs web Cogito Learning . Pustaka terdiri dari kelas-kelas berikut, yang ada dalam paket ca.javajeff.lexanyang disertakan dalam kode yang dapat diunduh untuk artikel ini:
  • Lexan: penganalisis leksikal;
  • LexanException: pengecualian dilemparkan ke konstruktor kelasLexan;
  • LexException: pengecualian diberikan jika sintaksis yang salah terdeteksi selama analisis leksikal;
  • Token: nama dengan atribut ekspresi reguler;
  • TokLex: token/pasangan token.
Konstruktor Lexan(java.lang.Class tokensClass)membuat penganalisis leksikal baru. Dibutuhkan satu argumen dalam bentuk objek kelas java.lang.Classyang sesuai dengan tipe konstanta class static Token. Dengan menggunakan Reflection API, konstruktor membaca semua konstanta Tokenke dalam array nilai Token[]. Jika Tokentidak ada konstanta, pengecualian akan diberikan LexanException. Ekspresi Reguler di Java, Bagian 5 - 2Kelas Lexanjuga menyediakan dua metode berikut:
  • Metode ini mengembalikan daftar lexer ini;List getTokLexes() Token
  • Метод void lex(String str)melakukan analisis leksikal dari string masukan [dengan hasilnya ditempatkan] ke dalam daftar nilai bertipe TokLex. Jika ditemukan karakter yang tidak cocok dengan pola array mana pun Token[], pengecualian akan diberikan LexException.
Kelas LexanExceptiontidak memiliki metode; ia menggunakan metode yang diwariskan untuk mengembalikan pesan pengecualian getMessage(). Sebaliknya, kelas LexExceptionmenyediakan metode berikut:
  • Metode ini int getBadCharIndex()mengembalikan posisi karakter yang tidak cocok dengan pola penanda mana pun.
  • Metode ini String getText()mengembalikan teks yang dianalisis ketika pengecualian dibuat.
Kelas Tokenmengganti metode toString()untuk mengembalikan nama penanda. Ini juga menyediakan metode String getPattern()yang mengembalikan atribut ekspresi reguler token. Kelas TokLexmenyediakan metode Token getToken()yang mengembalikan tokennya. Ia juga menyediakan metode String getLexeme()yang mengembalikan tokennya.

Demonstrasi perpustakaan Lexan

Untuk mendemonstrasikan cara kerja perpustakaan, Lexansaya menulis sebuah aplikasi LexanDemo. Terdiri dari kelas LexanDemo, BinTokens, MathTokensdan NoTokens. Kode sumber untuk aplikasi LexanDemoditunjukkan pada Listing 2. Listing 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();
   }
}
Metode main()di Listing 2 memanggil utilitas lex()untuk mendemonstrasikan analisis leksikal menggunakan Lexan. Setiap panggilan ke metode ini diteruskan ke kelas token dalam objek Classdan string yang akan diurai. Metode ini lex()pertama-tama membuat objek kelas Lexandengan meneruskan objek tersebut Classke konstruktor kelas Lexan. Dan kemudian memanggil metode lex()kelas Lexanpada string itu. Jika analisis leksikal berhasil, metode kelas TokLexdipanggil untuk mengembalikan daftar objek . Untuk masing-masing objek ini, metode kelasnya dipanggil untuk mengembalikan token dan metode kelasnya dipanggil untuk mengembalikan token. Kedua nilai tersebut dicetak ke output standar. Jika analisis leksikal gagal, salah satu pengecualian atau akan dilempar dan ditangani sebagaimana mestinya . Untuk singkatnya, mari kita pertimbangkan hanya kelas yang membentuk aplikasi ini . Listing 3 menunjukkan kode sumbernya. Listing 3. Deskripsi sekumpulan token untuk bahasa matematika 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_]*");
}
Listing 3 menunjukkan bahwa kelas MathTokensmenggambarkan urutan konstanta bertipe Token. Masing-masing diberi nilai suatu objek Token. Konstruktor untuk objek ini menerima string yang merupakan nama penanda, bersama dengan ekspresi reguler yang menjelaskan semua string karakter yang terkait dengan penanda tersebut. Untuk kejelasan, sebaiknya nama string penanda sama dengan nama konstanta, tetapi ini tidak diperlukan. Ekspresi Reguler di Java, Bagian 5 - 3Posisi konstanta Tokendalam daftar penanda sangatlah penting. Konstanta yang terletak lebih tinggi dalam daftar Tokenakan diutamakan daripada yang terletak di bawah. Misalnya, saat bertemu sin, Lexan memilih token, FUNCbukan ID. Jika token IDmendahului token FUNC, maka token tersebut akan dipilih.

Mengkompilasi dan menjalankan aplikasi LexanDemo

Kode yang dapat diunduh untuk artikel ini mencakup arsip lexan.zipyang berisi semua file distribusi Lexan. Buka paket arsip ini dan buka subdirektori demosdari direktori root lexan. Jika Anda menggunakan Windows, jalankan perintah berikut untuk mengkompilasi file kode sumber aplikasi demo:
javac -cp ..\library\lexan.jar *.java
Jika kompilasi berhasil, jalankan perintah berikut untuk menjalankan aplikasi demo:
java -cp ..\library\lexan.jar;. LexanDemo
Anda akan melihat hasil 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
Pesan tersebut Неожиданный символ во входном тексте: 20muncul sebagai akibat dari pelemparan pengecualian LexanExceptionkarena fakta bahwa kelas BinTokenstidak mendeklarasikan konstanta Tokendengan nilai 2sebagai ekspresi reguler. Perhatikan bahwa pengendali pengecualian mengeluarkan posisi karakter yang tidak sesuai yang diperoleh dari analisis leksikal teks. Pesan token yang hilang adalah hasil dari pengecualian yang dilempar LexExceptionkarena NoTokenstidak ada konstanta yang dideklarasikan di kelas Token.

Di balik layar

Lexanmenggunakan kelas Lexan sebagai mesinnya. Lihatlah implementasi kelas ini di Listing 4 dan perhatikan kontribusi ekspresi reguler dalam membuat mesin dapat digunakan kembali. Listing 4. Membuat arsitektur penganalisa leksikal berdasarkan ekspresi reguler
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);
      }
   }
}
Kode metode ini lex()didasarkan pada kode yang disediakan dalam postingan blog "Menulis Parser di Java: Generator Token" di situs web Cogito Learning. Baca postingan ini untuk mempelajari lebih lanjut tentang bagaimana Lexan menggunakan Regex API untuk mengkompilasi kode. Ekspresi Reguler di Java, Bagian 5 - 4

Kesimpulan

Ekspresi reguler adalah alat berguna yang dapat berguna bagi pengembang mana pun. Regex API dari bahasa pemrograman Java membuatnya mudah digunakan dalam aplikasi dan perpustakaan. Sekarang setelah Anda memiliki pemahaman dasar tentang ekspresi reguler dan API ini, lihat dokumentasi SDK java.util.regexuntuk mempelajari lebih lanjut tentang ekspresi reguler dan metode Regex API tambahan.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION