Форум программистов, компьютерный форум CyberForum.ru

Си-шные строки, как вытащить подстроку - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 42, средняя оценка - 4.79
besh]<a
 Аватар для besh]<a
12 / 10 / 1
Регистрация: 02.11.2009
Сообщений: 194
05.03.2012, 22:37     Си-шные строки, как вытащить подстроку #1
Есть ли для строк типа char*, wchar_t* стандартная функция, которая вытаскивает подстроку, как в классе string.substring(int pos, int count)?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.03.2012, 22:37     Си-шные строки, как вытащить подстроку
Посмотрите здесь:

Удаления со строки подстроку! C++
C++ Удалить из строки S1 первую подстроку, совпадающую с S2
6. Вводится 2 строки. Найти их самую длинную общую подстроку. C++
C++ Как эффективно заменить подстроку в строке на другую подстроку?
Строки. Выделить подстроку, которая соответствует записи целого числа. C++
Строки. Удалить из строки S1 последнюю подстроку, совпадающую с S2 C++
C++ Удалить из строки S последнюю подстроку,совпадающую с S0.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
go
Эксперт C++
3584 / 1364 / 128
Регистрация: 16.04.2009
Сообщений: 4,528
05.03.2012, 23:11     Си-шные строки, как вытащить подстроку #2
Не припомню. Но вот почему бы самому не реализовать? Вот список функций для char* (хедер string.h) http://www.cplusplus.com/reference/clibrary/cstring/

Добавлено через 4 минуты
Цитата Сообщение от go Посмотреть сообщение
Но вот почему бы самому не реализовать?
Например так
C
1
2
3
4
5
6
const char* const substr(char* s, size_t pos, size_t count)
{
   static char buf[BUFSIZ];
   memset(buf, '\0', BUFSIZ);
   return strncpy(buf, s + pos, count);
}
Добавлено через 25 минут
А лучше так
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>
 
const char* const substr(char* s, size_t pos, size_t count)
{
   static char buf[BUFSIZ];
   buf[sizeof buf - 1] = '\0';
   if ( count >= BUFSIZ )
      return NULL;
   else
      return strncpy(buf, s + pos, count);
}
 
int main(void)
{
   char *s = "Hello world";
   printf("%s\n", substr(s, 6, 5));
}
http://liveworkspace.org/code/19f593...9c50a3e9e54a44
easybudda
Модератор
Эксперт С++
 Аватар для easybudda
9383 / 5433 / 916
Регистрация: 25.07.2009
Сообщений: 10,428
06.03.2012, 00:19     Си-шные строки, как вытащить подстроку #3
Цитата Сообщение от go Посмотреть сообщение
const char* const substr(char* s, size_t pos, size_t count)
Модификатор доступа у возвращаемого функцией значения в С - UB. Может и работать, но лучше так не делать.
Цитата Сообщение от go Посмотреть сообщение
return strncpy(buf, s + pos, count);
Тоже не комильфо. Из биэсдишного мануала:
The strncpy() function copies at most len characters from src into dst.
If src is less than len characters long, the remainder of dst is filled
with `\0' characters. Otherwise, dst is not terminated.
...
The following copies as many characters from input to buf as will fit and
NUL terminates the result. Because strncpy() does not guarantee to NUL
terminate the string itself, this must be done explicitly.

char buf[1024];

(void)strncpy(buf, input, sizeof(buf) - 1);
buf[sizeof(buf) - 1] = '\0';
То есть опять же может работать, может не работать...

Я бы как-то так сделал:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <string.h>
 
/* Копирует в dst не больше cnt символов из src начиная с позиции pos.
Память под принимающую строку должна быть заранее выделена с учётом завершающего нуля. */
char * substr(char * dst, const char * src, size_t pos, size_t cnt){
    size_t len;
    
    if ( ! dst || ! src || strlen(src) < pos )
        return NULL;
    
    if ( ( len = strlen(src + pos) ) > cnt )
        len = cnt;
    strncpy(dst, src + pos, len);
    dst[len] = '\0';
    
    return dst;
}
 
int main(void){
    char src[BUFSIZ], dst[BUFSIZ];
    size_t pos, cnt;
    
    while ( printf("String: ") && fgets(src, BUFSIZ, stdin) && *src != '\n'
        && printf("Start pos: ") && scanf("%u", &pos) == 1
        && printf("Count: ") &&  scanf("%u%*c", &cnt) == 1 )
            printf("Result: %s\n", substr(dst, src, pos, cnt));
    
    return 0;
}
go
Эксперт C++
3584 / 1364 / 128
Регистрация: 16.04.2009
Сообщений: 4,528
06.03.2012, 14:02     Си-шные строки, как вытащить подстроку #4
Цитата Сообщение от easybudda Посмотреть сообщение
Модификатор доступа у возвращаемого функцией значения в С - UB. Может и работать, но лучше так не делать.
Это почему?


Цитата Сообщение от easybudda Посмотреть сообщение
Тоже не комильфо.
Не согласен. Здесь-то Вы не правы точно

Добавлено через 1 минуту
Прототип, описанный в заголовочном файле string.h:
char *strncpy (char *dst, const char *src, size_t len);
dst — указатель на буфер назначения.
src — указатель на исходную строку.
len — максимальное количество копируемых символов (см. раздел Безопасность ниже).
Функция копирует из строки src в буфер dst не более чем len символов (включая нулевой символ), не гарантируя завершения строки нулевым символом (если длина строки src больше или равна len). Если длина строки src меньше len, то буфер добивается до len нулями.
У меня даже строка 7 лишняя.
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
06.03.2012, 14:45     Си-шные строки, как вытащить подстроку #5
Но вот static массив то зачем
go
Эксперт C++
3584 / 1364 / 128
Регистрация: 16.04.2009
Сообщений: 4,528
06.03.2012, 14:51     Си-шные строки, как вытащить подстроку #6
Цитата Сообщение от fasked Посмотреть сообщение
Но вот static массив то зачем
Потому что возвращается указатель, на его память. Иначе память будет освобождена
-=ЮрА=-
Заблокирован
Автор FAQ
06.03.2012, 15:07     Си-шные строки, как вытащить подстроку #7
besh]<a, Ниже крайне простой и вместе с тем крайне функциональный код,
для функции substr даже строковых библиотек не нужно будетРаботает и возвращает подстроки абсолютно любой длинны т.к. в коде есть динамическое выделение памяти, а не константный буфер как во всех постах выше
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
using namespace std;
 
char * substr(const char * text, int beg, int end)
{
    int i;
    char *sub = 0;
    int len = end - beg;
    if(text)//Ïðîâåðÿåì Г*ГҐ ïóñòîé ëè ââîä
    if(text + beg)//Ïðîâåðÿåì ñóùåñòâîâГ*Г*ГЁГҐ Гў ГІГҐГЄГ±ГІГҐ ïîçèöèè beg
    if(0 < len)//Ïðîâåðÿåì êîððåêòГ*îñòü ГЇГ*Г°Г*ìåòðîâ ГЄГ®Г*ГҐГ¶ äîëæåГ* áûòü áîëüøå Г*Г*Г·Г*Г«Г*
    if((sub = new char[1 + len]))//Åñëè end ïðåâîñõîäèò ïîñëåäГ*ГѕГѕ
        //ïîçèöèþ ГІГҐГЄГ±ГІГ* Г*ГЁГ·ГҐГЈГ® Г±ГІГ°Г*ГёГ*îãî âûäåëèì Г·ГіГІГј áîëüøå ГЇГ*ìÿòè Г·ГҐГ¬ Г*Г*äî
    {
        //ÏðèìèòèâГ*îå êîìïèðîâГ*Г*ГЁГҐ, Г¤Г*æå òåêñòîâûõ áèáëèîòåê Г*ГҐ Г*Г*äî áóäåò
        for(i = beg; text[i] != '\0' && i < end; i++)
            sub[i - beg] = text[i];
        sub[i - beg] = '\0';//Íîëü òåðìèГ*Г*òîð ГўГЄГ®Г*öå ñòðîêè
    }
    return sub;
}
 
int main()
{
    char text[] = "abra kadabra";
    cout<<"input : "<<text<<endl;
    //ГЉ ïðìåðó ГЇГіГ±ГІГј áóäåò ïîäñòðîêГ* Г± 5-ГЈГ® ГЇГ® 15-Г© ñèìâîë
    //ГЄГ±ГІГ*ГІГЁ Гў text ìåГ*ГјГёГҐ Г·ГҐГ¬ 15 ñèìâîëîâ Г*Гі âîò Г§Г*îäГ*Г® ГЁ ïðîâåðèì
    //êîððåêòГ*îñòü Г°Г*áîòû substr
    cout<<"output: ";
    char * sub  = substr(text, 5 , 11);
    if(sub)
    {
        cout<<sub<<endl;
        delete [] sub;
    }
    else
        cout<<"Error substr\n";
    system("pause");
    return 0;
}
Скрин работы прилагаю
Миниатюры
Си-шные строки, как вытащить подстроку  
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
06.03.2012, 15:22     Си-шные строки, как вытащить подстроку #8
Цитата Сообщение от go Посмотреть сообщение
Потому что возвращается указатель, на его память. Иначе память будет освобождена
Статические переменные - это, во-первых, ограничение длины строки, а во-вторых невозможность сохранения этого самого возвращаемого указателя на продолжетельное время (несколько вызовов функции). Тут придется либо использовать копирование строки, что есть неоптимально. А в лсучае многопоточности придется добавлять мьютекс на каждый вызов функции.
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Работает и возвращает подстроки абсолютно любой длинны т.к. в коде есть динамическое выделение памяти, а не константный буфер как во всех постах выше
Опять же не есть плюс для функции библиотечного характера. Если мне понадобится статчиеский массив, то я не смогу ее использовать. К тому же для C++ это вообще не актуально.
-=ЮрА=-
Заблокирован
Автор FAQ
06.03.2012, 15:44     Си-шные строки, как вытащить подстроку #9
Цитата Сообщение от fasked Посмотреть сообщение
Если мне понадобится статчиеский массив, то я не смогу ее использовать.
- можешь пояснить на примере???

Добавлено через 3 минуты
fasked, запиши в моём коде
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
char text[] = "abra kadabra";
вот так
static char text[] = "abra kadabra";
и всё отработает без проблем, думаю что то ты перемудрил

Добавлено через 8 минут
Если речь коснулась Си, ну ничем не отличающийся код со static char text[]
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <stdlib.h>
 
char * substr(const char * text, int beg, int end)
{
    int i;
    char *sub = 0;
    int len = end - beg;
    if(text)//Проверяем не пустой ли ввод
    if(text + beg)//Проверяем существование в тексте позиции beg
    if(0 < len)//Проверяем корректность параметров конец должен быть больше начала
    if((sub = (char *)malloc(1 + len)))//Если end превосходит последнюю
        //позицию текста ничего страшного выделим чуть больше памяти чем надо
    {
        //Примитивное компирование, даже текстовых библиотек не надо будет
        for(i = beg; text[i] != '\0' && i < end; i++)
            sub[i - beg] = text[i];
        sub[i - beg] = '\0';//Ноль терминатор вконце строки
    }
    return sub;
}
 
int main()
{
    static char text[] = "abra kadabra";
    printf("input : %s\n",text);
    //К прмеру пусть будет подстрока с 5-го по 15-й символ
    //кстати в text меньше чем 15 символов ну вот заодно и проверим
    //корректность работы substr
    printf("output: ");
    char * sub  = substr(text, 5 , 11);
    if(sub)
    {
        printf("%s\n",sub);
        free((void *)sub);
    }
    else
        printf("Error substr\n");
    getchar();
    return 0;
}
Вот и проверка http://codepad.org/vPp56BAX
Не знаю что тут ещё разбирать, все работает вот и всё...
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
06.03.2012, 16:14     Си-шные строки, как вытащить подстроку #10
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Не знаю что тут ещё разбирать, все работает вот и всё...
Речь не о том работает или нет, речь о дизайне. Если я не хочу, чтобы функция выделяла память, то я не могу ее использовать. Потому что она делает это всегда. К тому же мне еще надо контролировать это, освобождать память. На мой взгляд выделять и освобождать память разными сущностями вообще некрасиво (за редкими исключениями).
Простой выход - не заботится о памяти и предоставить это сделать вызывающей стороне. Чем он вам всем не нравится, я не пойму? Посмотрите на стандартную библиотеку, сколько функций там выделяет память самостоятельно?
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
и всё отработает без проблем, думаю что то ты перемудрил
Я имею в виду строку-приемник. Посмотри на код easybudda - он гораздо гибче.
go
Эксперт C++
3584 / 1364 / 128
Регистрация: 16.04.2009
Сообщений: 4,528
06.03.2012, 16:22     Си-шные строки, как вытащить подстроку #11
Цитата Сообщение от fasked Посмотреть сообщение
Чем он вам всем не нравится, я не пойму?
Да писался некий аналог http://www.cplusplus.com/reference/s...string/substr/
А так я согласен, память лучше, чтобы выделял вызывающая сторона (ну а это еще 2 доп. параметра)

Добавлено через 3 минуты
Цитата Сообщение от easybudda Посмотреть сообщение
Я бы как-то так сделал:
http://codepad.org/6ZKn10Xd
-=ЮрА=-
Заблокирован
Автор FAQ
06.03.2012, 16:28     Си-шные строки, как вытащить подстроку #12
Цитата Сообщение от fasked Посмотреть сообщение
Потому что она делает это всегда. К тому же мне еще надо контролировать это, освобождать память. На мой взгляд выделять и освобождать память разными сущностями вообще некрасиво (за редкими исключениями).
Простой выход - не заботится о памяти и предоставить это сделать вызывающей стороне. Чем он вам всем не нравится, я не пойму? Посмотрите на стандартную библиотеку, сколько функций там выделяет память самостоятельно?
- теперь понял к чему относилось замечание. Для случая когда не хотим заботиться о чистке, выносим переменную отвечающую за динамический массив в глобальные и предусматриваем чистку внутри функции, либо изобрести свой маханький класс. На счёт стандартных функций знаю лишь аналоги substr в CString и встречал в php, для char-ов string.h её вроди как и не содержит, поэтому програмисту нужно работать руками самому для реализации указанного функционала

Добавлено через 2 минуты
Чтобы не быть голословным
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Для случая когда не хотим заботиться о чистке, выносим переменную отвечающую за динамический массив в глобальные и предусматриваем чистку внутри функции
- привожу код
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <stdio.h>
#include <stdlib.h>
 
char *sub;
char * substr(const char * text, int beg, int end)
{
    int i;
    if(sub)
        free((void *)sub);
    sub = 0;
    int len = end - beg;
    if(text)//Ïðîâåðÿåì Г*ГҐ ïóñòîé ëè ââîä
    if(text + beg)//Ïðîâåðÿåì ñóùåñòâîâГ*Г*ГЁГҐ Гў ГІГҐГЄГ±ГІГҐ ïîçèöèè beg
    if(0 < len)//Ïðîâåðÿåì êîððåêòГ*îñòü ГЇГ*Г°Г*ìåòðîâ ГЄГ®Г*ГҐГ¶ äîëæåГ* áûòü áîëüøå Г*Г*Г·Г*Г«Г*
    if((sub = (char *)malloc(1 + len)))//Åñëè end ïðåâîñõîäèò ïîñëåäГ*ГѕГѕ
        //ïîçèöèþ ГІГҐГЄГ±ГІГ* Г*ГЁГ·ГҐГЈГ® Г±ГІГ°Г*ГёГ*îãî âûäåëèì Г·ГіГІГј áîëüøå ГЇГ*ìÿòè Г·ГҐГ¬ Г*Г*äî
    {
        //ÏðèìèòèâГ*îå êîìïèðîâГ*Г*ГЁГҐ, Г¤Г*æå òåêñòîâûõ áèáëèîòåê Г*ГҐ Г*Г*äî áóäåò
        for(i = beg; text[i] != '\0' && i < end; i++)
            sub[i - beg] = text[i];
        sub[i - beg] = '\0';//Íîëü òåðìèГ*Г*òîð ГўГЄГ®Г*öå ñòðîêè
    }
    return sub;
}
 
int main()
{
    static char text[] = "abra kadabra";
    printf("input : %s\n",text);
    //ГЉ ïðìåðó ГЇГіГ±ГІГј áóäåò ïîäñòðîêГ* Г± 5-ГЈГ® ГЇГ® 15-Г© ñèìâîë
    //ГЄГ±ГІГ*ГІГЁ Гў text ìåГ*ГјГёГҐ Г·ГҐГ¬ 15 ñèìâîëîâ Г*Гі âîò Г§Г*îäГ*Г® ГЁ ïðîâåðèì
    //êîððåêòГ*îñòü Г°Г*áîòû substr
    printf("output: ");
    char * sub  = substr(text, 5 , 11);
    if(sub)
        printf("%s\n",sub);
    else
        printf("Error substr\n");
    sub  = substr(text, 7 , 9);
    if(sub)
        printf("%s\n",sub);
    else
        printf("Error substr\n");
    getchar();
    return 0;
}
Добавлено через 50 секунд
Всё ок http://codepad.org/irb5mCfD
fasked
Эксперт C++
 Аватар для fasked
4925 / 2505 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
06.03.2012, 16:39     Си-шные строки, как вытащить подстроку #13
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Для случая когда не хотим заботиться о чистке, выносим переменную отвечающую за динамический массив в глобальные и предусматриваем чистку внутри функции
И получаем все недостатки использования статического массива, кроме ограничения по длине строки.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.03.2012, 21:16     Си-шные строки, как вытащить подстроку
Еще ссылки по теме:

выделить из строки наибольшую монотонную подстроку C++
Вывести подстроку данной строки, находящуюся между символами a и b C++
Как вытащить из строки значение? C++
Как скопировать подстроку из строки до определенного символа? Или удалить, начиная с этого символа C++
C++ Выделить подстроку из строки, использую char*

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
besh]<a
 Аватар для besh]<a
12 / 10 / 1
Регистрация: 02.11.2009
Сообщений: 194
12.03.2012, 21:16  [ТС]     Си-шные строки, как вытащить подстроку #14
Всем спасибо за ваши ответы.

Такая беда, когда внутри функции выделяется память оператором new, то в билдере vcl объекты не могут выполнить следующие операции, когда пытаешься сделать
C++
1
2
UnicodeString=substring(...); 
RichEdit->Lines->Add(substrin(...));
Вылетает с ошибкой. При использовании статического массива все нормально.

И еще при таком объявление
C++
1
wchar_t* word=L"hells bells";
, оператор
C++
1
delete [] word;
нужен? При запуске программы оба варианта работают нормально.

И еще один вопрос по по поводу функции возвращающей указатель, на который она выделила память. В след ситуации произойдет утечка памяти?
C++
1
strstr(str, substr(...))
Yandex
Объявления
12.03.2012, 21:16     Си-шные строки, как вытащить подстроку
Ответ Создать тему
Опции темы

Текущее время: 13:11. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru