Как найти повторяющуюся строку с помощью сопоставления с образцом?

У меня есть строка, похожая на эту:

[13:41:25] [100:Devnull]: 01:41:20, 13:41:21> |Hunit:Player-3693-07420299:DevnullYour [Chimaera Shot] hit |Hunit:Creature-0-3693-1116-3-87318-0000881AC4:Dungeoneer's Training DummyDungeoneer's Training Dummy 33265 Nature. 

Если вам интересно, это из World of Warcraft.

Я хотел бы закончить примерно так:

[13:41:25] [100:Devnull]: 01:41:20, 13:41:21> Your [Chimaera Shot] hit Dungeoneer's Training Dummy 33265 Nature. 

Если вы заметили, «Тренировочный манекен исследователя подземелий» печатается дважды. Мне удалось избавиться от первой части «| Hunit» примерно так:

str = "[13:41:25] [100:Devnull]: 01:41:20, 13:41:21> |Hunit:Player-3693-07420299:DevnullYour [Chimaera Shot] hit |Hunit:Creature-0-3693-1116-3-87318-0000881AC4:Dungeoneer's Training DummyDungeoneer's Training Dummy 33265 Nature."
str = string.gsub(str, "|Hunit:.*:.*Your", "Your")

Что возвращает это:

print(str)    # => [13:41:25] [100:Devnull]: 01:41:20, 13:41:21> Your [Chimaera Shot] hit |Hunit:Creature-0-3693-1116-3-87318-0000881AC4:Dungeoneer's Training DummyDungeoneer's Training Dummy 33265 Nature.

Затем я добавляю второй gsub:

str = string.gsub(str, "|Hunit:.*:", "")
print(str) # => [13:41:25] [100:Devnull]: 01:41:20, 13:41:21> Your [Chimaera Shot] hit Dungeoneer's Training DummyDungeoneer's Training Dummy 33265 Nature.

Но двойная строка «Тренировочный манекен исследователя подземелий», очевидно, повторяется.

Как я могу избавиться от дублированной строки? Эта строка может быть любой другой, в данном случае это «Тренировочный манекен исследователя подземелий», но это может быть и имя любой другой цели.


person dev404    schedule 19.03.2015    source источник


Ответы (1)


Вы можете попробовать что-то вроде этого:

str = "[13:41:25] [100:Devnull]: 01:41:20, 13:41:21> Your [Chimaera Shot] hit Dungeoneer's Training DummyDungeoneer's Training Dummy 33265 Nature."
-- find a string that starts with 'hit', has some number of non-digits
-- and ends with one or more digit and one or more characters.
-- these characters will be "captured" into three strings,
-- which are then passed to the "replacement" function.
-- the returned result of the function replaces the value in the string.
str = str:gsub("(hit%s+)([^%d]+)(%d+.+)", function(s1, s2, s3)
    local s = s2:gsub("%s+$","") -- drop trailing spaces
    if #s % 2 == 0 -- has an even number of characters
    and s:sub(0, #s / 2) -- first half
    == -- is the same
    s:sub(#s / 2 + 1) -- as the second half
    then -- return the second half
      return s1..s:sub(#s / 2 + 1)..' '..s3
    else
      return s1..s2..s3
    end
  end)
print(str)

Это печатает: [13:41:25] [100:Devnull]: 01:41:20, 13:41:21> Your [Chimaera Shot] hit Dungeoneer's Training Dummy

Этот код попытается извлечь имя цели и проверить, является ли имя полным дубликатом. Если совпадение не удается, возвращается исходная строка.

person Paul Kulchenko    schedule 19.03.2015
comment
Это делает это, хотя мне все еще требуется замыкающий 33265 Nature.. Не могли бы вы объяснить, что происходит в функции, которую вы использовали? Если не трудно. - person dev404; 20.03.2015
comment
После удаления 33265 Nature функция проверяет, можно ли разделить текущую строку на две половины, и проверяет, совпадают ли эти две половины. Добавлю еще комментарии... - person Paul Kulchenko; 20.03.2015
comment
Обновите решение, чтобы сохранить в нем 33265 Nature. - person Paul Kulchenko; 20.03.2015
comment
Ооо, я понял. Четное количество символов говорит о том, что это дубликат. Умный. Большое спасибо! - person dev404; 20.03.2015
comment
Верно; Я подумал, что [^] было бы полезно знать, если кто-то не знаком с ним, но %D определенно короче. - person Paul Kulchenko; 20.03.2015