Как я обрезаю пробел продвижения/запаздывания стандартным способом?

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

Например, ниже - класс ученика, который будет использовать его в нашем коде.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
168
задан Stephen 23 August 2011 в 02:09
поделиться

11 ответов

Если можно изменить строку:

// Note: This function returns a pointer to a substring of the original string.
// If the given string was allocated dynamically, the caller must not overwrite
// that pointer with the returned value, since the original pointer must be
// deallocated using the same allocator with which it was allocated.  The return
// value must NOT be deallocated using free() etc.
char *trimwhitespace(char *str)
{
  char *end;

  // Trim leading space
  while(isspace((unsigned char)*str)) str++;

  if(*str == 0)  // All spaces?
    return str;

  // Trim trailing space
  end = str + strlen(str) - 1;
  while(end > str && isspace((unsigned char)*end)) end--;

  // Write new null terminator character
  end[1] = '\0';

  return str;
}

, Если Вы не можете изменить строку, тогда можно использовать в основном тот же метод:

// Stores the trimmed input string into the given output buffer, which must be
// large enough to store the result.  If it is too small, the output is
// truncated.
size_t trimwhitespace(char *out, size_t len, const char *str)
{
  if(len == 0)
    return 0;

  const char *end;
  size_t out_size;

  // Trim leading space
  while(isspace((unsigned char)*str)) str++;

  if(*str == 0)  // All spaces?
  {
    *out = 0;
    return 1;
  }

  // Trim trailing space
  end = str + strlen(str) - 1;
  while(end > str && isspace((unsigned char)*end)) end--;
  end++;

  // Set output size to minimum of trimmed string length and buffer size minus 1
  out_size = (end - str) < len-1 ? (end - str) : len-1;

  // Copy trimmed string and add null terminator
  memcpy(out, str, out_size);
  out[out_size] = 0;

  return out_size;
}
157
ответ дан Dave Gray 23 November 2019 в 20:56
поделиться

Я только включаю код, потому что код, отправленный до сих пор, кажется субоптимальным (и у меня нет представителя для комментария все же.)

void inplace_trim(char* s)
{
    int start, end = strlen(s);
    for (start = 0; isspace(s[start]); ++start) {}
    if (s[start]) {
        while (end > 0 && isspace(s[end-1]))
            --end;
        memmove(s, &s[start], end - start);
    }
    s[end - start] = '\0';
}

char* copy_trim(const char* s)
{
    int start, end;
    for (start = 0; isspace(s[start]); ++start) {}
    for (end = strlen(s); end > 0 && isspace(s[end-1]); --end) {}
    return strndup(s + start, end - start);
}

strndup() расширение GNU. Если у Вас нет его или что-то эквивалентное, самокрутка. Например:

r = strdup(s + start);
r[end-start] = '\0';
0
ответ дан sfink 23 November 2019 в 20:56
поделиться

Лично, я прокрутил бы свое собственное. Можно использовать strtok, но необходимо заботиться с выполнением так (особенно при удалении начальных символов), что Вы знаете то, что память что.

Избавление от конечных пробелов легко, и довольно безопасно, поскольку можно просто вставить 0 поверх последнего пространства, рассчитав назад от конца. Избавление от продвижения пробелов означает перемещать вещи. Если Вы хотите сделать это на месте (вероятно, разумный), можно просто продолжать смещаться, все поддерживает один символ, пока нет никакого ведущего пространства. Или, чтобы быть более эффективными, Вы могли найти индекс первого непробела и сместить все назад на то число. Или, Вы могли просто использовать указатель на первый непробел (но тогда необходимо быть осторожными таким же образом, как Вы делаете с strtok).

0
ответ дан Ben 23 November 2019 в 20:56
поделиться

Вот тот, который смещает строку в первое положение Вашего буфера. Вы могли бы хотеть это поведение так, чтобы при динамичном выделении строки можно было все еще освободить его на том же указателе, которые обрезают () возвраты:

char *trim(char *str)
{
    size_t len = 0;
    char *frontp = str;
    char *endp = NULL;

    if( str == NULL ) { return NULL; }
    if( str[0] == '\0' ) { return str; }

    len = strlen(str);
    endp = str + len;

    /* Move the front and back pointers to address the first non-whitespace
     * characters from each end.
     */
    while( isspace((unsigned char) *frontp) ) { ++frontp; }
    if( endp != frontp )
    {
        while( isspace((unsigned char) *(--endp)) && endp != frontp ) {}
    }

    if( str + len - 1 != endp )
            *(endp + 1) = '\0';
    else if( frontp != str &&  endp == frontp )
            *str = '\0';

    /* Shift the string so that it starts at str so that if it's dynamically
     * allocated, we can still free it on the returned pointer.  Note the reuse
     * of endp to mean the front of the string buffer now.
     */
    endp = str;
    if( frontp != str )
    {
            while( *frontp ) { *endp++ = *frontp++; }
            *endp = '\0';
    }


    return str;
}

Тест для правильности:

int main(int argc, char *argv[])
{
    char *sample_strings[] =
    {
            "nothing to trim",
            "    trim the front",
            "trim the back     ",
            " trim one char front and back ",
            " trim one char front",
            "trim one char back ",
            "                   ",
            " ",
            "a",
            "",
            NULL
    };
    char test_buffer[64];
    int index;

    for( index = 0; sample_strings[index] != NULL; ++index )
    {
            strcpy( test_buffer, sample_strings[index] );
            printf("[%s] -> [%s]\n", sample_strings[index],
                                     trim(test_buffer));
    }

    /* The test prints the following:
    [nothing to trim] -> [nothing to trim]
    [    trim the front] -> [trim the front]
    [trim the back     ] -> [trim the back]
    [ trim one char front and back ] -> [trim one char front and back]
    [ trim one char front] -> [trim one char front]
    [trim one char back ] -> [trim one char back]
    [                   ] -> []
    [ ] -> []
    [a] -> [a]
    [] -> []
    */

    return 0;
}

Исходный файл был trim.c. Скомпилированный с 'cc trim.c-o обрезка'.

32
ответ дан indiv 23 November 2019 в 20:56
поделиться

Мое решение. Строка должна быть изменяемой. Преимущество выше некоторых из других решений, что это перемещает часть непространства в начало, таким образом, можно продолжать использовать старый указатель, в случае, если необходимо освободить () его позже.

void trim(char * s) {
    char * p = s;
    int l = strlen(p);

    while(isspace(p[l - 1])) p[--l] = 0;
    while(* p && isspace(* p)) ++p, --l;

    memmove(s, p, l + 1);
}   

Эта версия создает копию строки с strndup () вместо того, чтобы редактировать его на месте. strndup () требует _GNU_SOURCE, поэтому возможно, необходимо сделать собственный strndup () с malloc () и strncpy ().

char * trim(char * s) {
    int l = strlen(s);

    while(isspace(s[l - 1])) --l;
    while(* s && isspace(* s)) ++s, --l;

    return strndup(s, l);
}
21
ответ дан jkramer 23 November 2019 в 20:56
поделиться

Я не уверен, что Вы считаете "безболезненными".

струны до являются довольно болезненными. Мы можем найти первое положение непробельного символа тривиально:

while (isspace(* p)) p++;

Мы можем найти последнее положение непробельного символа с двумя подобными тривиальными перемещениями:

while (* q) q++;
do { q--; } while (isspace(* q));

(я сэкономил Вас боль использования * и ++ операторы одновременно.)

вопрос теперь - то, что Вы делаете с этим? Тип данных под рукой не является действительно большим устойчивым кратким обзором String, который легок думать о, но вместо этого действительно едва больше, чем массив байтов устройства хранения данных. Испытывая недостаток в устойчивом типе данных, невозможно записать функцию, которая сделает то же как PHperytonby's chomp функция. Что было бы такая функция в возврате C?

1
ответ дан jfm3 23 November 2019 в 20:56
поделиться

Пользуйтесь строковая библиотека , например:

Ustr *s1 = USTR1(\7, " 12345 ");

ustr_sc_trim_cstr(&s1, " ");
assert(ustr_cmp_cstr_eq(s1, "12345"));

..., как Вы говорите, это - "общая" проблема, да необходимо включать приблизительно один #include, и он не включен в libc, но не идите, изобретая собственное задание взлома, хранящее случайные указатели, и тот путь size_t только приводит к переполнению буфера.

1
ответ дан James Antill 23 November 2019 в 20:56
поделиться
#include "stdafx.h"
#include "malloc.h"
#include "string.h"

int main(int argc, char* argv[])
{

  char *ptr = (char*)malloc(sizeof(char)*30);
  strcpy(ptr,"            Hel  lo    wo           rl   d G    eo rocks!!!    by shahil    sucks b i          g       tim           e");

  int i = 0, j = 0;

  while(ptr[j]!='\0')
  {

      if(ptr[j] == ' ' )
      {
          j++;
          ptr[i] = ptr[j];
      }
      else
      {
          i++;
          j++;
          ptr[i] = ptr[j];
      }
  }


  printf("\noutput-%s\n",ptr);
        return 0;
}
1
ответ дан 23 November 2019 в 20:56
поделиться

Немного поздно в игру, но я брошу в бой свои распорядки. Они, вероятно, не самые эффективные, но я считаю, что они правильные и простые (с rtrim () , выходящим за пределы диапазона сложности):

#include <ctype.h>
#include <string.h>

/*
    Public domain implementations of in-place string trim functions

    Michael Burr
    michael.burr@nth-element.com
    2010
*/

char* ltrim(char* s) 
{
    char* newstart = s;

    while (isspace( *newstart)) {
        ++newstart;
    }

    // newstart points to first non-whitespace char (which might be '\0')
    memmove( s, newstart, strlen( newstart) + 1); // don't forget to move the '\0' terminator

    return s;
}


char* rtrim( char* s)
{
    char* end = s + strlen( s);

    // find the last non-whitespace character
    while ((end != s) && isspace( *(end-1))) {
            --end;
    }

    // at this point either (end == s) and s is either empty or all whitespace
    //      so it needs to be made empty, or
    //      end points just past the last non-whitespace character (it might point
    //      at the '\0' terminator, in which case there's no problem writing
    //      another there).    
    *end = '\0';

    return s;
}

char*  trim( char* s)
{
    return rtrim( ltrim( s));
}
0
ответ дан 23 November 2019 в 20:56
поделиться

Вот моя мини-библиотека C для обрезки левого, правого, обоих, всего, по месту и по отдельности, а также обрезки набора указанных символов (или пробелов по умолчанию).

содержимое strlib.h:

#ifndef STRLIB_H_
#define STRLIB_H_ 1
enum strtrim_mode_t {
    STRLIB_MODE_ALL       = 0, 
    STRLIB_MODE_RIGHT     = 0x01, 
    STRLIB_MODE_LEFT      = 0x02, 
    STRLIB_MODE_BOTH      = 0x03
};

char *strcpytrim(char *d, // destination
                 char *s, // source
                 int mode,
                 char *delim
                 );

char *strtriml(char *d, char *s);
char *strtrimr(char *d, char *s);
char *strtrim(char *d, char *s); 
char *strkill(char *d, char *s);

char *triml(char *s);
char *trimr(char *s);
char *trim(char *s);
char *kill(char *s);
#endif

содержимое strlib.c:

#include <strlib.h>

char *strcpytrim(char *d, // destination
                 char *s, // source
                 int mode,
                 char *delim
                 ) {
    char *o = d; // save orig
    char *e = 0; // end space ptr.
    char dtab[256] = {0};
    if (!s || !d) return 0;

    if (!delim) delim = " \t\n\f";
    while (*delim) 
        dtab[*delim++] = 1;

    while ( (*d = *s++) != 0 ) { 
        if (!dtab[0xFF & (unsigned int)*d]) { // Not a match char
            e = 0;       // Reset end pointer
        } else {
            if (!e) e = d;  // Found first match.

            if ( mode == STRLIB_MODE_ALL || ((mode != STRLIB_MODE_RIGHT) && (d == o)) ) 
                continue;
        }
        d++;
    }
    if (mode != STRLIB_MODE_LEFT && e) { // for everything but trim_left, delete trailing matches.
        *e = 0;
    }
    return o;
}

// perhaps these could be inlined in strlib.h
char *strtriml(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_LEFT, 0); }
char *strtrimr(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_RIGHT, 0); }
char *strtrim(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_BOTH, 0); }
char *strkill(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_ALL, 0); }

char *triml(char *s) { return strcpytrim(s, s, STRLIB_MODE_LEFT, 0); }
char *trimr(char *s) { return strcpytrim(s, s, STRLIB_MODE_RIGHT, 0); }
char *trim(char *s) { return strcpytrim(s, s, STRLIB_MODE_BOTH, 0); }
char *kill(char *s) { return strcpytrim(s, s, STRLIB_MODE_ALL, 0); }

Все это делает одна основная процедура. Он обрезается на месте, если src == dst , в противном случае он работает как подпрограммы strcpy . Он обрезает набор символов, указанных в строке delim , или пробел, если он равен нулю. Он обрезает влево, вправо, оба и все (как tr). В этом нет ничего особенного, и он выполняет итерацию по строке только один раз. Некоторые люди могут жаловаться, что обрезка справа начинается слева, однако в любом случае не требуется strlen, который начинается слева. (Так или иначе, вы должны добраться до конца строки для правильной обрезки, чтобы вы могли выполнять работу на ходу.) Могут быть аргументы по поводу конвейерной обработки, размеров кеша и тому подобного - кто знает . Поскольку решение работает слева направо и повторяется только один раз, его можно расширить для работы с потоками. Ограничения: он не работает со строками unicode .

10
ответ дан 23 November 2019 в 20:56
поделиться

Вот функция, чтобы сделать то, что Вы хотите. Это должно заботиться о вырожденных случаях, где строка является всем пробелом. Необходимо передать в буфере вывода и длине буфера, что означает, что необходимо передать в буфере, который Вы выделяете.

void str_trim(char *output, const char *text, int32 max_len)
{
    int32 i, j, length;
    length = strlen(text);

    if (max_len < 0) {
        max_len = length + 1;
    }

    for (i=0; i<length; i++) {
        if ( (text[i] != ' ') && (text[i] != '\t') && (text[i] != '\n') && (text[i] != '\r')) {
            break;
        }
    }

    if (i == length) {
        // handle lines that are all whitespace
        output[0] = 0;
        return;
    }

    for (j=length-1; j>=0; j--) {
        if ( (text[j] != ' ') && (text[j] != '\t') && (text[j] != '\n') && (text[j] != '\r')) {
            break;
        }
    }

    length = j + 1 - i;
    strncpy(output, text + i, length);
    output[length] = 0;
}

, если операторы в циклах могут, вероятно, быть заменены isspace (текст [я]) или isspace (текст [j]) для создания строк немного легче читать. Я думаю, что сделал, чтобы они установили этот путь, потому что были некоторые символы, на которые я не хотел тестировать, но похоже, что я покрываю весь пробел теперь:-)

-1
ответ дан Mark 23 November 2019 в 20:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: