C - самая большая строка из большого - PullRequest
1 голос
/ 03 октября 2009

Так что, скажите, пожалуйста, как бы я мог получить наибольшую непрерывную цепочку букв из цепочки мусора в C? Вот пример:

char *s = "(2034HEY!!11   th[]thisiswhatwewant44";

Вернется ...

thisiswhatwewant

На днях у меня было это в викторине ... и это сводило меня с ума (все еще есть), пытаясь понять это!

UPDATE:

Мои ошибки, ребята, я забыл включить тот факт, что единственная функция, которую вам разрешено использовать, это функция strlen. Таким образом, делая это сложнее ...

Ответы [ 7 ]

3 голосов
/ 03 октября 2009

Uae strtok(), чтобы разбить вашу строку на токены, используя все не-буквенные символы в качестве разделителей, и найти самый длинный токен.

Чтобы найти самый длинный токен, вам потребуется организовать хранилище для токенов - я бы использовал связанный список.

Так просто, как это.

EDIT

Хорошо, если strlen() - единственная разрешенная функция, вы можете сначала найти длину исходной строки, затем пройти по ней и заменить все не-буквенные символы на NULL - в основном это то, что делает strtok().

Затем вам нужно второй раз просмотреть измененную исходную строку, продвигая по одному токену за раз, и найти самый длинный, используя strlen().

1 голос
/ 21 октября 2009

Зачем вообще использовать strlen()? Вот моя версия, которая вообще не использует никаких функций.

#ifdef UNIT_TEST
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#endif

/*
// largest_letter_sequence()
// Returns a pointer to the beginning of the largest letter
//   sequence (including trailing characters which are not letters)
//   or NULL if no letters are found in s
// Passing NULL in `s` causes undefined behaviour
// If the string has two or more sequences with the same number of letters
//   the return value is a pointer to the first sequence.
// The parameter `len`, if not NULL, will have the size of the letter sequence
//
// This function assumes an ASCII-like character set
//   ('z' > 'a'; 'z' - 'a' == 25; ('a' <= each of {abc...xyz} <= 'z'))
//   and the same for uppercase letters
// Of course, ASCII works for the assumptions :)
*/
const char *largest_letter_sequence(const char *s, size_t *len) {
  const char *p = NULL;
  const char *pp = NULL;
  size_t curlen = 0;
  size_t maxlen = 0;

  while (*s) {
    if ((('a' <= *s) && (*s <= 'z')) || (('A' <= *s) && (*s <= 'Z'))) {
      if (p == NULL) p = s;
      curlen++;
      if (curlen > maxlen) {
        maxlen = curlen;
        pp = p;
      }
    } else {
      curlen = 0;
      p = NULL;
    }
    s++;
  }
  if (len != NULL) *len = maxlen;
  return pp;
}

#ifdef UNIT_TEST
void fxtest(const char *s) {
  char *test;
  const char *p;
  size_t len;

  p = largest_letter_sequence(s, &len);
  if (len && (len < 999)) {
    test = malloc(len + 1);
    if (!test) {
      fprintf(stderr, "No memory.\n");
      return;
    }
    strncpy(test, p, len);
    test[len] = 0;
    printf("%s ==> %s\n", s, test);
    free(test);
  } else {
    if (len == 0) {
      printf("no letters found in \"%s\"\n", s);
    } else {
      fprintf(stderr, "ERROR: string too large\n");
    }
  }
}

int main(void) {
  fxtest("(2034HEY!!11   th[]thisiswhatwewant44");
  fxtest("123456789");
  fxtest("");
  fxtest("aaa%ggg");
  return 0;
}
#endif
1 голос
/ 03 октября 2009

Что определяет «хорошие» подстроки по сравнению со многими другими - быть только строчными буквами? (т.е. без пробелов, цифр, знаков препинания, прописных букв и т. д.)

Каким бы ни был предикат P, который проверяет, является ли персонаж "хорошим", один проход s с применением P к каждому символу позволяет легко определить начало и конец каждого "цикла хороших символов" и запомнить и выбрать самый длинный. В псевдокоде:

longest_run_length = 0
longest_run_start = longest_run_end = null
status = bad
for i in (all indices over s):
  if P(s[i]):  # current char is good
    if status == bad:  # previous one was bad
      current_run_start = current_run_end = i
      status = good
    else: # previous one was also good
      current_run_end = i
  else:  # current char is bad
    if status == good:  # previous one was good -> end of run
      current_run_length = current_run_end - current_run_start + 1
      if current_run_length > longest_run_length:
        longest_run_start = current_run_start
        longest_run_end = current_run_end
        longest_run_length = current_run_length
      status = bad

# if a good run ends with end-of-string:
if status == good:  # previous one was good -> end of run
  current_run_length = current_run_end - current_run_start + 1
  if current_run_length > longest_run_length:
    longest_run_start = current_run_start
    longest_run_end = current_run_end
    longest_run_length = current_run_length
1 голос
/ 03 октября 2009

Это похоже на стандартную утилиту UNIX 'strings'.

Отслеживание самого длинного набора печатных символов, оканчивающихся на NULL. Пройдите через байты, пока не поразите печатного персонажа. Начните считать. Если вы нажали непечатный символ, прекратите считать и выбросьте начальную точку. Если вы нажмете NULL, проверьте, больше ли длина текущего цикла, чем предыдущий держатель записи. Если это так, запишите его и начните искать следующую строку.

0 голосов
/ 03 октября 2009

Другой вариант.

#include <stdio.h>
#include <string.h>

int main(void)
{
        char s[] = "(2034HEY!!11   th[]thisiswhatwewant44";
        int len = strlen(s);
        int i = 0;
        int biggest = 0;
        char* p = s;

        while (p[0])
        {
                if (!((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z')))
                {
                        p[0] = '\0';
                }

                p++;
        }

        for (; i < len; i++)
        {
                if (s[i] && strlen(&s[i]) > biggest)
                {
                        biggest = strlen(&s[i]);
                        p = &s[i];
                }
        }

        printf("%s\n", p);
        return 0;
}
0 голосов
/ 03 октября 2009

Пока я ждал, что вы опубликуете это как вопрос, я что-то кодировал.

Этот код перебирает строку, переданную «самой длинной» функции, и когда он находит первую из последовательности букв, он устанавливает на нее указатель и начинает считать ее длину. Если это самая длинная последовательность букв из всех увиденных, она устанавливает другой указатель (указатель 'maxStringStart') на начало этой последовательности, пока не найдет более длинную.

В конце он выделяет достаточно места для новой строки и возвращает указатель на нее.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int isLetter(char c){

    return ( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') );

}

char *longest(char *s) {

    char *newString = 0;
    int maxLength = 0;
    char *maxStringStart = 0;
    int curLength = 0;
    char *curStringStart = 0;

    do {

        //reset the current string length and skip this
        //iteration if it's not a letter
        if( ! isLetter(*s)) {
            curLength = 0;
            continue;
        }

        //increase the current sequence length. If the length before
        //incrementing is zero, then it's the first letter of the sequence:
        //set the pointer to the beginning of the sequence of letters
        if(curLength++ == 0) curStringStart = s;

        //if this is the longest sequence so far, set the
        //maxStringStart pointer to the beginning of it
        //and start increasing the max length.
        if(curLength > maxLength) {
            maxStringStart = curStringStart;
            maxLength++;
        }

    } while(*s++);

    //return null pointer if there were no letters in the string,
    //or if we can't allocate any memory.
    if(maxLength == 0) return NULL;
    if( ! (newString = malloc(maxLength + 1)) ) return NULL;

    //copy the longest string into our newly allocated block of
    //memory (see my update for the strlen() only requirement)
    //and null-terminate the string by putting 0 at the end of it.
    memcpy(newString, maxStringStart, maxLength);
    newString[maxLength + 1] = 0;

    return newString;

}

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

    int i;

    for(i = 1; i < argc; i++) {
        printf("longest all-letter string in argument %d:\n", i);
        printf("   argument: \"%s\"\n", argv[i]);
        printf("    longest: \"%s\"\n\n", longest(argv[i]));
    }

    return 0;

}

Это моё решение в простом C, без каких-либо структур данных.

Я могу запустить его в своем терминале так:

~/c/t $ ./longest "hello there, My name is Carson Myers." "abc123defg4567hijklmnop890"
longest all-letter string in argument 1:
   argument: "hello there, My name is Carson Myers."
    longest: "Carson"

longest all-letter string in argument 2:
   argument: "abc123defg4567hijklmnop890"
    longest: "hijklmnop"

~/c/t $

критерий того, что составляет букву, можно легко изменить в функции isLetter(). Например:

return ( 
    (c >= 'a' && c <= 'z') ||
    (c >= 'A' && c <= 'Z') ||
    (c == '.') || 
    (c == ' ') || 
    (c == ',') );

будет также считать точки, запятые и пробелы как «буквы».


согласно вашему обновлению:

заменить memcpy(newString, maxStringStart, maxLength); на:

int i;
for(i = 0; i < maxLength; i++)
    newString[i] = maxStringStart[i];

однако, эту проблему было бы намного легче решить с использованием стандартной библиотеки C:

char *longest(char *s) {

    int longest = 0;
    int curLength = 0;
    char *curString = 0;
    char *longestString = 0;
    char *tokens = " ,.!?'\"()@$%\r\n;:+-*/\\";

    curString = strtok(s, tokens);
    do {

        curLength = strlen(curString);
        if( curLength > longest ) {
            longest = curLength;
            longestString = curString;
        }

    } while( curString = strtok(NULL, tokens) );

    char *newString = 0;

    if( longest == 0 ) return NULL;
    if( ! (newString = malloc(longest + 1)) ) return NULL;

    strcpy(newString, longestString);

    return newString;

}
0 голосов
/ 03 октября 2009

Сначала определите «строка» и определите «мусор». Что вы считаете допустимой строкой без мусора? Запишите конкретное определение, которое вы можете запрограммировать - так пишутся спецификации программирования. Это последовательность буквенно-цифровых символов? Должно ли оно начинаться с буквы, а не с цифры?

Как только вы поймете это, вы сможете очень просто программировать. Начните с наивного метода обхода «мусора» в поисках того, что вам нужно. Как только вы это сделаете, найдите полезные функции библиотеки C (например, strtok), чтобы сделать код более простым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...