ترجمهای از راهنمای کوتاه عبارات منظم در جاوا را که توسط جف فریسن برای وبسایت javaworld نوشته شده است، در اختیار شما قرار میدهیم. برای سهولت در مطالعه مقاله را به چند قسمت تقسیم کرده ایم. این قسمت قسمت پایانی است. عبارات با قاعده در جاوا، قسمت 1 عبارات با قاعده در جاوا، قسمت 2 عبارات با قاعده در جاوا، قسمت 3 عبارات با قاعده در جاوا، قسمت 4
عبارات منظم بسیار کارآمدتر از تحلیلگرهای واژگانی مبتنی بر حالت هستند، که باید با دست نوشته شوند و به طور کلی نمی توان آنها را دوباره استفاده کرد. نمونهای از یک تحلیلگر واژگانی مبتنی بر عبارت منظم، JLex است ، یک مولد واژگانی برای زبان جاوا که از عبارات منظم برای تعریف قوانین برای تجزیه یک جریان داده ورودی به نشانهها استفاده میکند. مثال دیگر Lexan است.
استفاده از عبارات منظم برای تحلیل واژگانی
یکی از کاربردهای مفیدتر عبارات منظم، کتابخانه ای از کدهای قابل استفاده مجدد برای انجام تحلیل واژگانی است که جزء کلیدی هر کامپایلر یا اسمبلر است. در این مورد، جریان ورودی کاراکترها به یک جریان خروجی از نشانهها گروهبندی میشود - نامهایی برای دنبالههایی از کاراکترها که معنای مشترکی دارند. به عنوان مثال، با مواجهه با دنباله کاراکترهایc
, o
, u
, n
, t
, e
, r
در جریان ورودی، تحلیلگر واژگانی می تواند یک نشانه ID
(شناسه) را خروجی دهد. دنباله نویسه های متناظر با نشانه، واژگان نامیده می شود.
بیشتر در مورد نشانگرها و واژگان |
---|
توکن هایی مانند ID می توانند با بسیاری از توالی کاراکتر مطابقت داشته باشند. در مورد چنین نشانه هایی، رمز واقعی مربوط به توکن نیز توسط کامپایلر، اسمبلر یا سایر ابزارهایی که نیاز به تحلیل واژگانی دارد مورد نیاز است. برای نشانههایی که نشاندهنده یک دنباله خاص از کاراکترها هستند، مانند نشانهای که PLUS فقط با کاراکتر مطابقت دارد + ، نشانه واقعی مورد نیاز نیست زیرا میتوان آن را از روی نشانه شناسایی کرد. |
آشنایی با لکسان
Lexan یک کتابخانه جاوا قابل استفاده مجدد برای تحلیل واژگانی است. این بر اساس کد از مجموعه پست وبلاگ Writing a Parser in Java در وب سایت Cogito Learning است . این کتابخانه از کلاس های زیر تشکیل شده است که در بستهca.javajeff.lexan
موجود در کد قابل دانلود این مقاله موجود است:
Lexan
: تحلیلگر واژگانی;LexException
: در صورت تشخیص نحو نادرست در طول تجزیه و تحلیل واژگانی، استثنا پرتاب می شود.Token
: نام با ویژگی عبارت منظم.TokLex
: جفت توکن/ژتون.
LexanException
: استثنا پرتاب شده در سازنده کلاسLexan;
Lexan(java.lang.Class tokensClass)
یک تحلیلگر واژگانی جدید ایجاد می کند. به یک آرگومان در قالب یک شی کلاس java.lang.Class
مطابق با کلاس ثابت نوع نیاز دارد static Token
. با استفاده از Reflection API، سازنده تمام ثابت ها را Token
در آرایه ای از مقادیر می خواند Token[]
. اگر Token
هیچ ثابتی وجود نداشته باشد، یک استثنا پرتاب می شود LexanException
. کلاس 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()
Lexan
getToken()
TokLex
getLexeme()
LexanException
LexException
MathTokens
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
. سازنده برای این شی، رشته ای را دریافت می کند که نام نشانگر است، همراه با یک عبارت منظم که تمام رشته های کاراکتر مرتبط با آن نشانگر را توصیف می کند. برای وضوح، مطلوب است که نام رشته نشانگر با نام ثابت یکی باشد، اما این مورد نیاز نیست. موقعیت ثابت Token
در لیست نشانگرها مهم است. ثابت هایی که در بالاترین لیست قرار دارند، Token
نسبت به مواردی که در زیر قرار دارند، اولویت دارند. به عنوان مثال، هنگام مواجه شدن با ، Lexan به جای sin
علامت، توکن را انتخاب می کند . اگر نشانگر قبل از نشانگر بود ، انتخاب می شد. FUNC
ID
ID
FUNC
کامپایل و اجرای برنامه 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
اعلام نمی کند . توجه داشته باشید که کنترل کننده استثنا موقعیت نویسه نامناسب به دست آمده از تحلیل واژگانی متن را خروجی می دهد. پیام از دست رفته نشانه ها نتیجه یک استثنا است که در کلاس اعلان نشده است . Token
2
LexException
NoTokens
Token
پشت صحنه
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 برای کامپایل کد بیشتر بدانید.
نتیجه
عبارات منظم ابزار مفیدی است که می تواند برای هر توسعه دهنده ای مفید باشد. Regex API زبان برنامه نویسی جاوا استفاده از آنها را در برنامه ها و کتابخانه ها آسان می کند. اکنون که درک اولیه ای از عبارات منظم و این API دارید، نگاهی به مستندات SDK بیندازیدjava.util.regex
تا حتی بیشتر در مورد عبارات منظم و روش های Regex API اضافی بیاموزید.
GO TO FULL VERSION