Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.222.117.109] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Есть константа(текстовые смайлы):
Const Smiles:array[1..7] of string = ('*^_^*','*8)*','*8(*','*-_-*','*^0^*','*^p^*','*8p*'); Есть абстрактный тест, который может содержать произвольное количество вхождений смайлов из константы. Пример текста: message *^0^**8)* message2 *^0^* message3 message4 message5 Как мне разбить текст на составляющие: message *^0^* *8)* message2 *^0^* message3 message4 message5 при этом если это смайл, то вернуть номер смайла в константе. текст и смайлы могут быть и не разделены пробелом. Смайлы имеют разную длину. В лоб не получается сделать. |
Сообщ.
#2
,
|
|
|
Чтоб текст разбивать, определись, что есть лексемы, а что - разделители.
|
Сообщ.
#3
,
|
|
|
min@y™
разделители константы. все остальное лексемы |
Сообщ.
#4
,
|
|
|
Простой конечный автомат. Вход в состояние "внутри смайла" - когда встретил звездочку, штатный выход по второй звездочке, нештатный - если не совпадает с одной из констант.
В общем случае - алгоритм Ахо-Корасик, но для этой задачи он излишне сложен. |
Сообщ.
#5
,
|
|
|
Цитата MBo @ Вход в состояние "внутри смайла" - когда встретил звездочку Да, так получилось: Const MaxSmiles=7; Smiles:array[1..7] of string = ('*^_^*','*8)*','*8(*','*-_-*','*^0^*','*^p^*','*8p*'); Var sIn,sOut,Smile:string; i,i2,slength,CharNum:integer; begin Sin:='message *^0^* *8)* message2 *^0^* message3 message4 message5'; CharNum:=0; For i:=1 to length(SIn) do begin inc(CharNum); If SIn[CharNum]='*' then Begin For i2:=1 to MaxSmiles do Begin SLength:=length(Smiles[i2]);//длина смайла Smile:=copy(SIn,CharNum,SLength);//смайл в тексте If Smile=Smiles[i2] then begin CharNum:=CharNum+SLength-1; If (SOut<>'')and(SOut<>' ') then ShowMessage(SOut); SOut:=''; ShowMessage(Smile); break; end; End; End else begin SOut:=SOut+SIn[charnum]; If(Length(SIn)=CharNum)then ShowMessage(sOut); end; end; end; |
Сообщ.
#6
,
|
|
|
Эх, это совсем не конечный автомат, а каждый раз копирование всех образцов и сравнение с ними. В таком случае можно было обойтись PosEx для поиска начальной/конечной звездочек и Pos для поиска кусочка в строке-объединении всех смайлов.
|
Сообщ.
#7
,
|
|
|
MBo
разделители могут идти не в том порядке, которые представлены в константе, значит придется определять какой стоит первым, какой вторым и т.д. если вы видите что код может быть существенно сокращен, буду благодарен за новый. |
Сообщ.
#8
,
|
|
|
Быстродействие важно? Текущая скорость устраивает?
|
Сообщ.
#9
,
|
|
|
Цитата MBo @ Быстродействие важно? Текущая скорость устраивает? нет, не важно Скорость значения не имеет |
Сообщ.
#10
,
|
|
|
Тогда не стоит заморачиваться, код будет объёмнее.
|
Сообщ.
#11
,
|
|
|
Кстати вопрос к знатокам, через stringlist можно сделать подобное? Передать в качестве разделителя массив разделителей?
|
Сообщ.
#12
,
|
|
|
Массив нельзя. Есть какие-то функции, принимающие набор разделителей, но зачем? У тебя один разделитель, внутри смайлов он не содержится, поэтому делай PosEx начала, проверяй, смайл ли идет следующим, если нет - переходи на следующий разделитель, повторить до окончания строки.
|
Сообщ.
#13
,
|
|
|
^D^ima
Можно вот так вот. Главное правильно за эскейпить смайлы в регулярке. function TForm1.ReplaceCC(const Match: TMatch): string; const NL=#$000D#$000A; begin Result := NL+Match.Value+NL; end; procedure TForm1.Button2Click(Sender: TObject); var regex: TRegEx; input: string; myEval: TMatchEvaluator; begin input := 'message *^0^* *8)* message2 *^0^* message3 message4 message5.';; regex.Create('(\*\^_\^\*)|(\*8\)\*)|(\*\^0\^\*)'); myEval := ReplaceCC; Memo1.Text := regex.Replace(input, myEval); end; message *^0^* *8)* message2 *^0^* message3 message4 message5. Добавлено '\*\^0\^\*' - правильное экранирование '\*\^\0\^\*' - неправильное экранирование |
Сообщ.
#14
,
|
|
|
Pavia
Спасибо, любая библиотека для регулярки скушает это? '(\*\^_\^\*)|(\*8\)\*)|(\*\^0\^\*)' Добавлено У тебя регулярка учитывает 2 смайла всего? У меня их уже 17 |
Сообщ.
#15
,
|
|
|
Цитата ^D^ima @ Спасибо, любая библиотека для регулярки скушает это? Я не такой большой знаток регулярок. Но тут используется стандартные операторы \ | (). Полагаю проглотит любая перловская библиотека. Если не пойдёт попробуйте без скобок. Но из практики у всех библиотек регулярок свои заскоки несовместимые между собой. Добавлено Цитата ^D^ima @ У тебя регулярка учитывает 2 смайла всего? У меня их уже 17 3 но можно написать сколько хочешь (смайл1)|(смайл2)|(смайл3)|(смайл4)|(смайл5)|(смайл6) и так далее. Только XE требует правильного экранирования. http://docwiki.embarcadero.com/RADStudio/S...lar_Expressions |