#java
#java
Вопрос:
В настоящее время я пишу анализатор для языка, который я создаю, которому необходимо проверить, соответствует ли текущая часть потока одному из элементов в переданном массиве. Краткая версия кода:
public abstract class Parser {
private StringReader reader; //This is a BufferedReader with rollback
//A single string lookahead method
public boolean lookahead(String toMatch, boolean rollback) throws ParseException {
char c;
//Mark the current position in the stream, so we can come back to it if needed
MarkToken currentMark = reader.mark();
//Iterate through the toMatch and check if each character matches
for(int i = 0; i < toMatch.length(); i) {
c = reader.nextChar();
if(toMatch.charAt(i) != c) {
break;
}
}
//Get the current image
String got = reader.currentImage(currentMark);
//If we don't have a match, rollback if necessary and return false
if(!got.equals(toMatch)) {
if(rollback) {
reader.rollBack();
}
return false;
}
return true;
}
//The String[] lookahead method
public int lookahead(String[] toMatch, boolean rollback) throws ParseException {
if(toMatch.length == 1) {
//If there is only one element in toMatch, send it to a cheaper function
if(lookahead(toMatch[0]))
return 0;
else return 1;
} else {
int maxLength = toMatch[0].length();
//We use this variable to keep track of how many valid choices are left
int choicesLeft = toMatch.length;
int i, j;
char current;
//Mark the current position in the stream, so we can come back to it if needed
MarkToken mark = s().mark();
//Get the length of the longest string in toMatch
for(i = 1; i < toMatch.length; i) {
maxLength = Math.max(maxLength, toMatch[i].length());
}
//Go up to the length of the longest string
for(i = 0; i < maxLength; i) {
//Get the next character from the stream
current = reader.nextChar();
//If we've reached the end of the stream:
if(current == -1 || current == 'uffff') {
//Get back a character in the stream
reader.rollbackChar();
//And check to see if we have a match
return ArrayUtils.indexOf(toMatch, reader.currentImage(mark));
}
//Go through each item in toMatch
for(j = 0; j < toMatch.length; j) {
if(toMatch[j] != null) {
//Check to see if the character matches or not
if(toMatch[j].charAt(i) != current) {
//We null an item in toMatch if it doesn't apply any more
toMatch[j] = null;
--choicesLeft;
}
}
}
//If we only have one choice left, see if there is a match (will return -1 if not)
if(choicesLeft == 1) {
return ArrayUtils.indexOf(toMatch, reader.currentImage(mark));
}
}
//If there is no
if(rollback) {
reader.rollBackTo(mark);
}
}
return -1;
}
}
Эта функция будет вызвана для проверки, содержит ли поток определенные символы (. .* $@ // » ‘ «»» «‘ и т.д.) И потреблять их с жадностью.
Я бы предоставлял массив максимум из 10-15 элементов одновременно, поэтому удаление элементов из массива может быть не лучшей оптимизацией.
Есть ли более эффективный способ сделать это, определенные методы или циклы, которые я должен использовать?
Комментарии:
1. Это сильно зависит от того, что сейчас неэффективно. Если считыватель работает медленно, вы можете сравнивать со всеми элементами массива сразу, по одному символу за раз. Если вы выполняете тысячи проверок и хотите ускорить их, извлекайте данные из программы чтения порциями и вместо этого проверяйте эти порции. Каков ваш текущий профиль производительности и где узкое место для требуемой эффективности и сценариев? Если вы не можете ответить на этот вопрос, значит, вы не готовы задать вопрос о том, как повысить производительность этого кода.
2. Код просто работает? Попробуйте это codereview.stackexchange.com .
3. После того, как я написал это, я понял, что если поток был длиннее любого из вариантов, метод вернул бы значение -1. Я полагаю, единственный способ, которым вы могли бы обойти это, — если вы добрались до этой стадии, вы отправляете обратно самое длинное совпадение?
4. Тогда я сначала заставлю код работать!
![]()
5. Вы когда-нибудь заставляли этот код работать?