#python #string #parsing
#питон #строка #разбор
Вопрос:
У меня есть такая длинная строка:
[left-ctrl]bhbhbhblbhbhblbhblblbhbl[left-ctrl][left-ctrl]blbhblbhblbbjbjbjblblbhblbhbhblbk[left-ctrl][left-ctrl]bhblblbjbjbkbjbkbjbkbkbh[left-ctrl]kkkkkk[left-cmd][tab][left-cmd][del]su[del][del]cut [del][left-shift];[left-shift][del]s[left-shift];
Фактическая строка намного длиннее (160 000 символов). Я хочу рассматривать [...]
как один символ b
, например h
, … Как?
Отредактированный:
Проблема в том, что один [
и ]
может выглядеть так [[[[[
, ]]]]]]
. Моя текущая идея состоит в том, чтобы использовать некоторую библиотеку для предварительного поиска точки появления управляющих символов, таких как [left-ctrl]
, [cmd]
,…, Затем используйте a cursor
для циклического просмотра и будьте особенно осторожны, когда курсор находится в этой специальной точке . Но эта идея может занять несколько раундов, чтобы предварительно найти эти особые точки. Я думаю о том, есть ли более простой способ сделать это эффективно. Что касается использования библиотеки, мне просто лень самому реализовывать алгоритм KMP.
Обратите внимание, что, возможно, появится один ]
без [
. Например. [left-ctrl]]hbh[left-ctrl]
.
Комментарии:
1. Это не имеет отношения к играм. @KJ
2. Я отредактировал свою проблему. И я не думаю, что ваше поведение тоже соответствует руководящим принципам. Я думаю, что стоит спросить, прежде чем «угадывать» намерения людей. Вы хотите сказать, что каждый вопрос на этом сайте должен сочетаться с некоторыми кодами? @KJ
3. Я не знаю, почему ты пытаешься решить мою проблему. Нажатия клавиш записываются инструментом CLI, который я не могу изменить результат. Чтобы изменить его, как вы сказали, мне все равно сначала нужно разобрать строку. Ты действительно знаешь, о чем говоришь? @KJ
4.Это соглашение об избежании для специальных кодов ключей неоднозначно для некоторых последовательностей ключей. Например, будет невозможно отличить последовательность отдельных символов от одного управляющего символа.
[
d
e
l
]
[del]
Возможно , вы могли бы заставить источник избегать скобок, чтобы они никогда не использовались в качестве одиночных символов (например[open-bracket]
, и[close-bracket]
или удвоить их[[
и]]
). Это сделало бы синтаксический анализ намного проще и надежнее.5. Я удалю свой ответ, потому что я неправильно понял часть вопроса, как @AlainT. указал, и я не хочу повторять их ответ, который очень хорош.
Ответ №1:
Вариант 1: Ручной синтаксический анализ
Вы можете определить функцию итератора, которая накапливает заключенные в квадратные скобки символы и выдает специальные ключи в качестве ключевых слов при обнаружении соответствующих скобок:
def keyCodes(iKeys,maxLength=30): special = "" for c in iKeys: if len(special) gt;= maxLength: # maximum code length yield from special # flush characters special = "" if c == "[": # start of special char if special: yield from special # flush prev. individual chars special = c elif c == "]" and special: # closing bracket special = c if len(special)gt;2: yield special # special code else: yield from special # empty [], not a code special = "" # reset elif special: special = c # accumulate special code else: yield c # return simple chars yield from special # flush trailing chars
Выход:
keys = "[left-ctrl]bhbhbhblbhbhblbhblblbhbl[left-ctrl][left-ctrl]blbhblbhblbbjbjbjblblbhblbhbhblbk[left-ctrl][left-ctrl]bhblblbjbjbkbjbkbjbkbkbh[left-ctrl]kkkkkk[left-cmd][tab][left-cmd][del]su[del][del]cut [del][left-shift];[left-shift][del]s[left-shift];" for code in keyCodes(keys): print(code) [left-ctrl] b h b h b h b l b h b h b l b h b l b l b h b l [left-ctrl] [left-ctrl] b l b h b l b h b l b b j b j b j b l b l b h b l b h b h b l b k [left-ctrl] [left-ctrl] b h b l b l b j b j b k b j b k b j b k b k b h [left-ctrl] k k k k k k [left-cmd] [tab] [left-cmd] [del] s u [del] [del] c u t [del] [left-shift] ; [left-shift] [del] s [left-shift] ;
Функция устанавливает максимальную длину special
переменной и сбрасывает ее, когда она достигает этого максимума. Это позволяет избежать хранения огромного значения в special
ожидании закрывающей скобки, которая может никогда не появиться.
Побочным преимуществом этого подхода является то, что он может использовать итератор в качестве входных данных (в отличие от регулярного выражения, для которого требуется вся строка заранее).
Обратите внимание, что условие ( if len(special)gt;2
) для определения того, следует ли выводить специальный код в виде строки или отдельных символов, вероятно, необходимо сверить со списком допустимых кодов специальных ключей (например if special in specialCodes
), в противном случае некоторые шаблоны ключей могут быть возвращены в виде специальных кодов, когда они не являются (например [xxx]
, или [@]
).
Вариант 2: Общий шаблон регулярного выражения
Если вы не возражаете против использования библиотеки, тот же результат можно получить с помощью регулярного выражения:
for code in re.findall(r'[[^][]{1,30}]|.',keys): print(code)
Выражение состоит из 2 частей, поиск выполняется в порядке приоритета (с использованием оператора pipe ( |
)):
[[^][]{1,30}]
: По крайней мере один символ между скобками (исключая другие скобки, максимум 30).
: любой отдельный символ
Как и в предыдущем решении, это может возвращать недопустимые специальные коды для последовательностей ключей, таких как [abc]
Вариант 3: Конкретный шаблон регулярного выражения
Если у вас есть список допустимых специальных кодов, вы можете создать регулярное выражение, чтобы извлечь их специально:
specialCodes = ['[tab]', '[left-ctrl]', '[left-shift]', '[del]', '[left-cmd]'] keyCodes = re.compile("|".join(re.escape(c) for c in specialCodes) "|.") for code in keyCodes.findall(keys): print(code)
Шаблон строится с использованием оператора pipe ( |
) для первого поиска специальных кодов и заканчивается одним символом ( .
) для обычных нажатий клавиш.
Известно, что регулярные выражения иногда работают медленно, поэтому я бы предложил сравнить производительность этих параметров с вашими данными, если обработка зависит от времени (в моем беглом сравнительном анализе регулярные выражения были более чем в 2 раза быстрее, чем при ручном анализе, при этом option2 немного быстрее, чем option3).
Комментарии:
1. 1 за вариант 3. Если мы не знаем возможных
[special-code]
значений, то наихудшим сценарием было бы, если бы мы столкнулись[
с началом строки, но тогда никогда не было совпадающего закрытия]
. Перечисление всех возможных[special-code]
значений дает регулярному выражению наилучшие шансы как можно скорее прекратить поиск закрывающей скобки. Аналогичным альтернативным улучшением, если все возможные специальные коды неизвестны, но мы знаем их максимальную длину, было бы использование{n,m}
вместоограничения длины поиска специального кода.
2. @Даниэль Шиллинг,
{n,m}
это очень хорошая идея для варианта 2 (а также для варианта 1). Я соответствующим образом скорректировал свой ответ, спасибо.