Как ускорить регулярные выражения iPhone с NSRegularExpression? - PullRequest
0 голосов
/ 01 марта 2011

Мое приложение iphone использует регулярные выражения (с NSRegularExpression) для выполнения вычислений с очень большим количеством строк (в тысячах). Это, конечно, занимает много времени. Каковы некоторые стратегии для ускорения регулярных выражений? Я изучал использование блоков, но не думаю, что это принесет какую-то пользу - они, по-видимому, в основном представляют собой лямбда-функции (т. Е. Эквивалентны lisp) и используются на Mac с несколькими ядрами. Очевидно, что текущий iPhone не имеет нескольких ядер.

Вот мой код:

NSString *replaceRegexPattern = @"([\\(|\\[].*?[\\)|\\]])|(^to )";
NSRegularExpression *replaceRegex = [[NSRegularExpression regularExpressionWithPattern:replaceRegexPattern
                                                                              options:NSRegularExpressionCaseInsensitive
                                                                               error:nil] retain];
NSArray *myArray = <some data>;
NSString *myString, *compareValue;
for (i = 0; i < [myArray count]; i++) {
    myString = [myArray objectAtIndex:i];
    compareValue = [replaceRegex stringByReplacingMatchesInString:myString
                                                          options:0
                                                            range:NSMakeRange(0, [myString length])
                                                     withTemplate:@""];
    // do things with compareValue

}

Чтобы ответить на вопрос ниже, моя цель в этом коде состоит в том, чтобы удалить любой текст в моей строке, который либо заключен в скобки, либо начинается с «to». Вот несколько примеров:

  • Привет (До свидания) -> Привет
  • Привет (До свидания [n]) -> Привет
  • Сказать -> Сказать
  • Сказать (pf) -> Сказать

Ответы [ 3 ]

1 голос
/ 01 марта 2011

Вы уверены, что регулярные выражения - правильный инструмент для этого?

Если все, что вы пытаетесь сделать, это удалить текст в скобках, простой цикл char-by-char в строке может сделать это очень легко, и даже правильно обрабатывать вложенные парены.

В псевдокоде:

 nesting_level = 0;
 while more_chars {
       c = next_char;
       if c == '(' or c == '[') 
           ++nesting_level;
       else if c == ')' or c == ']'
           --nesting_level;   // check for nesting_level < 0 here?
       else if nesting_level == 0
           result += c;
 }

Очевидно, сделайте свои собственные тесты, но, возможно, вы получите лучшую производительность, если не будете использовать регулярные выражения.

(и если вы хотите обнаружить плохо сформированные вещи типа "(привет]", вы можете добавить к этому простой рекурсивный спуск)

0 голосов
/ 01 марта 2011

Лучший способ ускорить это регулярное выражение - использовать квантификаторы притяжений:

NSString *replaceRegexPattern = 
    @"^to\\s++|\\[[^\\[\\]]*+\\]|\\([^()]*+\\)";

В тех случаях, когда совпадение невозможно, поскольку открывающая скобка не соответствует правильной закрывающей скобке, *+ предотвращает возврат, который, как мы знаем, был бы бессмысленным.Но успешных попыток совпадения также более эффективны, потому что движку регулярных выражений не нужно сохранять информацию о состоянии, которая делает возможным возврат.

Как отметил Тим, это не будет совпадатьвложенные экземпляры скобок того же типа, как ((foo)) или [[bar]]. будет соответствовать любому количеству квадратных скобок в соответствующих скобках или наоборот.Для этого не требуется, чтобы эти внутренние скобки были правильно спарены, поэтому они будут соответствовать, например, (foo[) или [(bar))].Это относится и к вашему исходному регулярному выражению.

Включение открывающих скобок в классах символов предотвращает односторонние совпадения, такие как [[foo] или ((bar).

0 голосов
/ 01 марта 2011

Поскольку я не знаю, что именно вы пытаетесь сделать, трудно дать обоснованный совет, но похоже, что ваше регулярное выражение можно немного улучшить.

Вы действительно пытаетесь сопоставить строки типа (foo), [bar] и |baz|? Вам не нужен генератор | внутри классов символов, поэтому если вы не хотите соответствовать третьему примеру здесь, отбросьте | s.

Тогда, поскольку вы ожидаете строки типа (foo [bar] baz), вам нужно разделить два вида скобок, и вы также можете немного ускорить свое регулярное выражение:

@"^to |\\([^)]*\\)|\\[[^\\]]*\\]"

Сначала проверяется to в начале строки, затем идет поиск открывающей скобки / скобки, всего, кроме закрывающих скобок / скобок и закрывающей скобки / скобки. Это требует меньше возврата, так что, вероятно, немного быстрее.

Вы не сможете обрабатывать вложенные скобки / скобки одинакового вида ((foo (bar) baz)) с одним регулярным выражением, потому что это больше не является регулярным - если вы не запускаете операцию замены регулярного выражения несколько раз, по одному разу для каждого уровня вложенности , Таким образом, приведенный выше пример будет удален, если вы запустите regex replace дважды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...