Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Делфи. Ищу функцию типа Pos(s1,s2), но со стартом поиска не с 1 символа
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
GetSmart
Существует ли такая?
Или как это можно делать малой кровью без искажения оригинала и создания новой субстроки поиска (через Copy например) ?
_Артём_
Цитата(GetSmart @ Jan 23 2012, 17:50) *
Существует ли такая?
Или как это можно делать малой кровью без искажения оригинала и создания новой субстроки поиска (через Copy например) ?

Да вроде нет такой.
Так что остаётся передавать как параметр в свою функции и дальше с помощью Delete работать.
GetSmart
Ну ведь это на 99% такой же код, что и Pos(), только один дополнительный параметр. Почему никто не догадался сделать sad.gif
Профессионалы, блин.
AHTOXA
StrPos:
Что-то типа такого:
Код
function CountTokens(BigString, SubStr : string) : integer;
Var
  Token : PChar;
begin
  result := 0;
  Token := PChar(BigString);
  Token := StrPos(Token, PChar(SubStr));
  while (Token <> nil) do
  begin
    inc(result);
    Inc(Token);
  end;
end;
GetSmart
Цитата(AHTOXA @ Jan 23 2012, 21:29) *
StrPos:
Что-то типа такого:
...


А такая конструкция утечку памяти не создаст?
Код
Token := PChar(BigString);

это вроде создаёт почти копию строки в динамической памяти, а следующая команда затрёт (?) оригинальный адрес.

Кроме того, мне нужно работать в позициях оригинальной строки. То есть нужно эти адреса как-то преобразовывать в позиции.
ARV
Цитата(GetSmart @ Jan 23 2012, 19:50) *
Существует ли такая?

не катите бочку на профессионалов! такая функция есть!

Цитата
Delphi syntax:

function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;

Description

PosEx returns the index of SubStr in S, beginning the search at Offset. If Offset is 1 (default), PosEx is equivalent to Pos.

PosEx returns 0 if SubStr is not found, if Offset is greater than the length of S, or if Offset is less than 1.

у вас что, Delphi без справочной системы? все же на раз находится там!
GetSmart
Цитата(ARV @ Jan 23 2012, 21:41) *
не катите бочку на профессионалов! такая функция есть!

Код
[Error] ????.pas(597): Undeclared identifier: 'PosEx'

Что подключить надо?

Цитата(ARV @ Jan 23 2012, 21:41) *
у вас что, Delphi без справочной системы? все же на раз находится там!

Есть Хелп. Этой функции там нет.
ARV
а что за версия Delphi у вас такая?!
подключать надо StrUtils.
AHTOXA
Цитата(GetSmart @ Jan 23 2012, 22:40) *
А такая конструкция утечку памяти не создаст?
Код
Token := PChar(BigString);

это вроде создаёт почти копию строки в динамической памяти, а следующая команда затрёт (?) оригинальный адрес.

Нет, это просто преобразование типов, никаких копий.
Цитата(GetSmart @ Jan 23 2012, 22:40) *
Кроме того, мне нужно работать в позициях оригинальной строки. То есть нужно эти адреса как-то преобразовывать в позиции.

Элементарно:
Код
  Token := PChar(BigString);
  Start = Token;   // Запомним начало
  Token := StrPos(Token, PChar(SubStr));
  IndexInString := Token - Start + 1;  // Вычислим индекс в строке
GetSmart
Цитата(ARV @ Jan 23 2012, 21:46) *
а что за версия Delphi у вас такая?!
подключать надо StrUtils.

Делфи 5.
StrUtils не найден. Для начала попробую поискать.

Цитата(AHTOXA @ Jan 23 2012, 21:52) *
Нет, это просто преобразование типов, никаких копий.

Не может быть. Явно создаётся копия с #0 в конце строки. Даже указатель индивидуальный, явно будет отличаться от оригинальной строки.

Цитата(AHTOXA @ Jan 23 2012, 21:52) *
Элементарно:

Ок. А удалять Token я сам потом должен?
Потому как, когда один раз, то не ... жалко, а когда миллион раз, то надо об этом 7 раз подумать.

ЗЫ.
Самое главно, что хотелось бы иметь допустимость #0 байт внутри строк и при этом нормальной работы. Так что Сишные строки - это самый крайний ущербный вариант. PosEx запустить было бы идеально.
ARV
вы бы еще 3-ю версию юзали! самая ходовая 7-я версия - в ней есть очень много всего хорошего, и очень мало лишнего, что потом прилипло... рекомендую обновиться. еще рекомендую найти и скачать библиотеку JVCL - отличная бесплатная коллекция на все случаи жизни с открытыми исходниками.

если строки у вас "короткие", т.е. не WideString, то можно колупаться с посимвольным разбором так:
Код
var strptr : pchar;
    i : integer;
begin
   strptr = @my_str[1];
   // и далее strptr[0] - 1-й символ, как в Си. strptr можно менять, как угодно - все как в Си, только внутри my_str не будет 0 на конце.
   // strptr в функциях полностью "совместим" с типом string, т.е. можно так:
   i := Pos('тра-та-та', strptr);
   inc(strptr, i+1);
   // и так далее
end;
_Pasha
Цитата(GetSmart @ Jan 23 2012, 20:58) *
Делфи 5.
StrUtils не найден. Для начала попробую поискать.

Возьмите в комплекте FreePascal.org Какая Ы разница..
GetSmart
Цитата(ARV @ Jan 23 2012, 21:59) *
вы бы еще 3-ю версию юзали! самая ходовая 7-я версия

Щас попробую найти и пришпиндорить к 5-ой StrUtils.
AHTOXA
Цитата(GetSmart @ Jan 23 2012, 22:58) *
Не может быть. Явно создаётся копия с #0 в конце строки. Даже указатель индивидуальный, явно будет отличаться от оригинальной строки.

Да нет жеsm.gif Это просто указатель на char. Мы его наводим на первый символ строки. И начинаем по ней елозить. Всё.
Цитата
Ок. А удалять Token я сам потом должен?

Нет. Это просто указатель в середину строки. (Начинаю чувствовать себя попугаемsm.gif )
Цитата
Самое главно, что хотелось бы иметь допустимость #0 байт внутри строк и при этом нормальной работы. Так что Сишные строки - это самый крайний ущербный вариант. PosEx запустить было бы идеально.

Насчёт нуля - не уверен, надо проверять. PosEx могу запостить, но только завтра sm.gif
ARV
не советую. в 7-й версии заметно откорректирована библиотека VCL, через которую и происходили основные утечки. ПОЧТИ все дырки были устранены. так что приклеивать к 5-й версии что-то другое, тем более от FreePascal не советую. что советую - уже говорил.
AHTOXA
Вот, нашёл, strutils специально для D5: тыц!
GetSmart
Цитата(ARV @ Jan 23 2012, 22:13) *
не советую. в 7-й версии заметно откорректирована библиотека VCL, через которую и происходили основные утечки. ПОЧТИ все дырки были устранены. так что приклеивать к 5-й версии что-то другое, тем более от FreePascal не советую. что советую - уже говорил.

Функция Pos() и PosEx() не выделяют и не освобождают память. Утечка им не страшна. Главное, чтобы формат строк был тот же, а он тот же.
AHTOXA
Цитата(AHTOXA @ Jan 23 2012, 23:15) *
Вот, нашёл, strutils специально для D5


Гы! Сделано через StrPos! sm.gif
GetSmart
Цитата(AHTOXA @ Jan 23 2012, 22:10) *
Да нет жеsm.gif Это просто указатель на char. Мы его наводим на первый символ строки. И начинаем по ней елозить. Всё.

А откуда берётся #0 в конце этой же строки, если его там не было?

Цитата(AHTOXA @ Jan 23 2012, 22:15) *
Вот, нашёл, strutils специально для D5: тыц!

Скопировал к себе в проект только одну функцию. Скомпилилась.

Последний вопрос - она точно будет нормально работать со строками с #0-символами, разбросанными по строке? Дальше первого #0 будет продолжаться поиск?

Я чего-то сильно сильно сомневаюсь sad.gif
ARV
Цитата(GetSmart @ Jan 23 2012, 21:16) *
Функция Pos() и PosEx() не выделяют и не освобождают память. Утечка им не страшна. Главное, чтобы формат строк был тот же, а он тот же.

я вам и говорю, что утечки через VCL идут - а она у вас старая, дырявая... вы же жалуетесь на утечки - вот я и советую обновиться на менее дырявую... но дело ваше.
GetSmart
Цитата(ARV @ Jan 23 2012, 22:25) *
я вам и говорю, что утечки через VCL идут - а она у вас старая, дырявая... вы же жалуетесь на утечки - вот я и советую обновиться на менее дырявую... но дело ваше.

Ок. Попробую. Спасибо за подсказку.
_Ivana
Цитата(GetSmart @ Jan 23 2012, 19:27) *
Но хотелось бы не делать лишней работы, и узнать заранее что надо, а что не надо.

Моему дилетантскому имху кажется, что при процитированном подходе в первую очередь следует прислушаться к неоднократным советам ARV, а потом уже копать дальше при необходимости.

ЗЫ пока набирал пост, вы уже вняли голосу разума и методологически верной стратегии rolleyes.gif
AHTOXA
Цитата(GetSmart @ Jan 23 2012, 23:23) *
А откуда берётся #0 в конце этой же строки, если его там не было?

Вот тут не знаю. Возможно он в string предусмотрен изначально.
Цитата(GetSmart @ Jan 23 2012, 23:23) *
Последний вопрос - она точно будет нормально работать со строками с #0-символами, разбросанными по строке? Дальше первого #0 будет продолжаться поиск?

Если через StrPos - то вряд ли. Иначе как он определит конец строки?
Имхо, проще написать свою функциюsm.gif
GetSmart
Цитата(ARV @ Jan 23 2012, 21:41) *
не катите бочку на профессионалов! такая функция есть!

А не подскажете, PosEx из 7-й делфи будет работать со строками с #0 в середине?
Принимаются - Да, Нет, Не знаю sm.gif


Upd
И ещё вопрос:
На страницах HTML 100% гарантируется отсутствие символов #0 ?
sigmaN
Цитата
Принимаются - Да, Нет, Не знаю
я выбираю вариант "Не знаю"
Но позволю себе немного размышлений...
Кажется формат хранения строк в Delphi отличается от сишного тем, что #0 не должен являться признаком конца строки. Вмместо этого длилна строки известна заранее(кажется хранится в первом байте). Т.е. при использовании типа string - проблемы с нулем скорее всего быть не должно.
В конце концов несложный эксперимент раз и на всегда прояснит ситуацию. Но Delphi сейчас ставить как-то не хочется )
AHTOXA
Цитата(GetSmart @ Jan 23 2012, 23:53) *
А не подскажете, PosEx из 7-й делфи будет работать со строками с #0 в середине?
Принимаются - Да, Нет, Не знаю sm.gif

Насчёт седьмой - не скажу, а вот из десятой - будет. Вот оно:
CODE
(* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The implementation of function PosEx is subject to the
* Mozilla Public License Version 1.1 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Fastcode
*
* The Initial Developer of the Original Code is Fastcode
*
* Portions created by the Initial Developer are Copyright © 2002-2004
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Aleksandr Sharahov
*
* ***** END LICENSE BLOCK ***** *)
function PosEx(const SubStr, S: string; Offset: Integer = 1): Integer;
asm
test eax, eax
jz @Nil
test edx, edx
jz @Nil
dec ecx
jl @Nil

push esi
push ebx

mov esi, [edx-4] //Length(Str)
mov ebx, [eax-4] //Length(Substr)
sub esi, ecx //effective length of Str
add edx, ecx //addr of the first char at starting position
cmp esi, ebx
jl @Past //jump if EffectiveLength(Str)<Length(Substr)
test ebx, ebx
jle @Past //jump if Length(Substr)<=0

add esp, -12
add ebx, -1 //Length(Substr)-1
add esi, edx //addr of the terminator
add edx, ebx //addr of the last char at starting position
mov [esp+8], esi //save addr of the terminator
add eax, ebx //addr of the last char of Substr
sub ecx, edx //-@Str[Length(Substr)]
neg ebx //-(Length(Substr)-1)
mov [esp+4], ecx //save -@Str[Length(Substr)]
mov [esp], ebx //save -(Length(Substr)-1)
movzx ecx, byte ptr [eax] //the last char of Substr

@Loop:
cmp cl, [edx]
jz @Test0
@AfterTest0:
cmp cl, [edx+1]
jz @TestT
@AfterTestT:
add edx, 4
cmp edx, [esp+8]
jb @Continue
@EndLoop:
add edx, -2
cmp edx, [esp+8]
jb @Loop
@Exit:
add esp, 12
@Past:
pop ebx
pop esi
@Nil:
xor eax, eax
ret
@Continue:
cmp cl, [edx-2]
jz @Test2
cmp cl, [edx-1]
jnz @Loop
@Test1:
add edx, 1
@Test2:
add edx, -2
@Test0:
add edx, -1
@TestT:
mov esi, [esp]
test esi, esi
jz @Found
@String:
movzx ebx, word ptr [esi+eax]
cmp bx, word ptr [esi+edx+1]
jnz @AfterTestT
cmp esi, -2
jge @Found
movzx ebx, word ptr [esi+eax+2]
cmp bx, word ptr [esi+edx+3]
jnz @AfterTestT
add esi, 4
jl @String
@Found:
mov eax, [esp+4]
add edx, 2

cmp edx, [esp+8]
ja @Exit

add esp, 12
add eax, edx
pop ebx
pop esi
end;
GetSmart
AHTOXA, спасибо большое.
Так и вставлю эту функцию в свой прожект, чтоб не мучиться с StrUtils-ом.

Но всё равно любопытно по поводу HTML страниц и #0.
AHTOXA
Цитата(GetSmart @ Jan 24 2012, 11:27) *
Но всё равно любопытно по поводу HTML страниц и #0.

Я практически на 100% уверен, что там нет нулей. Ибо они формируются и обрабатываются кучей разных программ на сиsm.gif
ARV
1. функции, работающие со строками ПАСКАЛЕВСКОГО типа (без нуля в конце) могут содержать в своей середине сколько угодно нулей. в связи с этим PosEx работать будет.
2. увидел - мелькнуло слово HTML... тайна покрыта мраком, но если вы парсите HTML, то снова порекомендую вам JVCL - там в комплекте есть много вещей, которые вам помогут, в том числе функции, которые почти готовы для того, чтобы искать и находить в HTML-тексте нужные теги и т.п. Вы удивитесь: как много в этой библиотеке есть готовых решений! sm.gif
3. если вдруг вам нужно делать поиск и замену, то для этого так же есть готовая библиотечная функция (начиная с 7 версии). очень удобно.
GetSmart
Цитата(AHTOXA @ Jan 23 2012, 22:32) *
Вот тут не знаю. Возможно он в string предусмотрен изначально.

Действительно, за последним символом Делфа намеренно ставит #0. Обрезая строку на 1 символ несколько раз, на месте обрезанного появляется ноль. А уже за нулём может быть мусор.

Недокументированная фича?

PosEx из десятки отлично работает. Тем более на асме. Самый fast.
_Pasha
Pchar или string?
Напомню, если включено {$H+}, то это как раз описанный Вами случай. Надо выключить.
GetSmart
Цитата(_Pasha @ Jan 25 2012, 13:19) *
Pchar или string?
Напомню, если включено {$H+}, то это как раз описанный Вами случай. Надо выключить.

Именно "голый" string. Это AnsiString в динамической памяти.

H+ включено. Если выключаю, то куча ошибок компиляции.
_Pasha
Цитата(GetSmart @ Jan 25 2012, 11:31) *
H+ включено. Если выключаю, то куча ошибок компиляции.

Значит, с нулём в конце надо уважительно быть , вставлять его в середину и прочие фокусы недопустимы. Кстати, утечки при освобождении строки могут быть, если для определения ее длины используется strlen(). Подробностей не помню.
GetSmart
Цитата(_Pasha @ Jan 25 2012, 13:56) *
Значит, с нулём в конце надо уважительно быть , вставлять его в середину и прочие фокусы недопустимы. Кстати, утечки при освобождении строки могут быть, если для определения ее длины используется strlen(). Подробностей не помню.

Не. В делфе не так. ИМХО этот ноль - просто костыль для си-совместимости строк, которые могут выводиться куда-то функциями (винды) с сишными аргументами. Например в Application.MessageBox(). Там и преобразование адреса сделано через PChar(name). Хотя раньше из-за этого нуля я думал что создаётся временная копия.

Этот string ещё как-то криво типизируется в 5-ой делфе. Поставил опцию H-, оно заругалось, что в компоненте тип string, а у меня в проге ShortString (хотя указан string). Далее я поменял все string в проге на AnsiString. Опять ругается, что в компоненте string, а у меня в проге AnsiString. Хотя вроде не должен.
sigmaN
А там где-то в настройках компилятора есть что-то про этот ShortString.. подробностей опять таки не помню, дэлфей щас нет под рукой.
AHTOXA
Цитата(GetSmart @ Jan 25 2012, 13:45) *
Недокументированная фича?

Я где-то про это читал, так что немножко документированнаяsm.gif Но где читал - не помню.
Цитата(GetSmart @ Jan 25 2012, 15:11) *
Не. В делфе не так. ИМХО этот ноль - просто костыль для си-совместимости строк, которые могут выводиться куда-то функциями (винды) с сишными аргументами.

Именно. Дельфя обеспечивает ноль на позиции (длина строки + 1). При этом нули в самой строке вполне допустимы (но они обманут функции, принимающие в качестве аргумента PChar).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.