實現輸入字符串多指定範圍的截取輸出(c語言)

                         QQ:3020889729                                                                                 小蔡

本文章旨在於學習總結。

實現要求

  1. 首行輸入需要截取列標,可輸入多個,但應該是一一對應的(總是一對數字),以負數作爲輸入結束判斷。
  2. 輸入字符串——按列標要求截取輸出。

實現需要的庫

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

引用的函數

  1. strlen(x) :計算字符串長度
  2. strncpy(y,x,n) :複製x中指定長度字符串到y中
  3. exit() :異常退出

實現思路

/*
1.首先處理輸入的列標,將它們一一對應的保存到一個數組中,然後判斷結束。
2.然後對輸入的字符串進行與一對列標差的值對應的字符串截取,但是這裏用strncpy即可;
因爲有多對列標需要處理,所以會用到for循環。
(其它處理中的問題,在代碼中會具體分析)
*/

代碼(函數式編程)

讀取輸入的列標,並存入一個數組

用一個函數處理列標的讀取,傳入參數爲,事先創建好的整型數組的指針(首地址)和 數組大小。
(數組存儲需要處理的一個個列標)

//int columns[],聲明一個數組形參
int read_column_numbers(int columns[], int max)
{
    int num = 0;
    int ch;

    //獲取列標號
    // 判斷列標以及列標數目是否滿足條件
    // 負數,意味着列標錄入結束
    while(num < max && scanf("%d", &columns[num])  && columns[num] >= 0) 
    {
        num += 1;  // 準備下一個列標的存取和檢測
    }

    // 驗證列標數目是否爲偶數——輸入的有效列標應該是一一對應的
    if(num % 2 != 0)
    {
        puts("Last column number is not paired.");
        exit(EXIT_FAILURE);  // 輸入異常,發生中斷
    }

    // 丟棄最後一個數字之後的部分——截至輸入的回車(或文件結尾)之間的空白
    // 比如: 0 2 4 6 -1      'EOF'或者'\n'
    while( (ch = getchar()) != EOF && ch != '\n')
    {
        ;
    }

    return num;  // 返回擁有的列標總數
}

進行字符串截取

這個函數的參數爲:輸出字符串指針,輸入字符串指針,需要處理的列標總數,需要處理的列標數組。

void rearrange(char *output, char const *input,
            int n_columns, int const columns[])
{
    int col;  // 列標索引
    int output_col;  // 輸出行列標索引——即存儲開始索引
    int len;  // 輸入字符串長度
    int nchars;  // 每次允許的拼接字符長度

    len = strlen(input);
    output_col = 0;  // 初始爲0
    nchars = 0;

    for(col = 0; col < n_columns; col += 2)  // 每兩個列標進行一次操作
    {
        nchars = columns[col+1] - columns[col] + 1;  // 獲取兩個列標之間的差——即截取字符個數
		// 判斷列標是否超過輸入行字符串長度
		// 輸出行的索引不大於最大索引:MAX_INPUT - 1
        if(columns[col] >= len || output_col == MAX_INPUT - 1)  
        {
            break;
        }
        if(output_col + nchars > MAX_INPUT - 1)  // 如果截取字符個數加上輸出行索引超過最大索引時,進行截取重計算
        {
            nchars = MAX_INPUT - output_col - 1;
        }
        strncpy(output + output_col, input + columns[col], nchars);  // 通過複製來截取
        output_col += nchars; // 截取後,索引按截取複製的字符數增加——0+7->7,這意味着下一次拼接從7開始(7爲拼接位)
    }
    output[output_col] = '\0';  // 給字符串拼接位加上結束字符NUL,n索引下賦值'\0'
}

完整代碼

將以上兩個函數帶入main中,實現功能。

/*
**處理字符串**
程序要求:
①輸入第一行,爲字符串處理的列標號,末尾以負數結尾
②此後輸入的字符串,將以待處理的列標號來截取字符輸出
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_COLS 20  // 最多處理的列標數目
#define MAX_INPUT 1000  // 每行最多的列數——即字符串長度


int read_column_numbers(int columns[], int max);    // 讀取需要處理的列標號, 返回一共要處理的列標數目
void rearrange(char *output, char const *input,  int n_columns, int const columns[]);  // 實現字符串指定字符段截取, 返回的數據存在output中


int main(void)
{
    int n_columns;   // 需要處理的列標總數
    int columns[MAX_COLS];  // 存需要處理的列標
    char input[MAX_INPUT];  // 存儲輸入的行字符串
    char output[MAX_INPUT]; // 存儲輸出的行字符串

    n_columns = read_column_numbers(columns, MAX_INPUT);  // 返回需要處理的列表數目

    // 需要知道的是,gets返回一個指針,指針的值爲0時也不代表着沒有輸入行,僅僅是空行而已
    // 而沒有輸入行時(即文件結束),返回NULL指針(注意:NULL指針不能解引用*)
    while (NULL != gets(input))  // 輸入字符串_當不存在輸入行(文件結束-EOF_ctrl+z)時,返回NULL
    {
        printf("\nOriginal input : %s\n", input);  // 打印輸入的字符串
        rearrange(output, input, n_columns, columns);  // 獲取需要輸出的字符串
        printf("Rearranged line: %s\n\n", output);  // 打印輸出的字符串
    }
    return EXIT_SUCCESS; //return 0;
}

int read_column_numbers(int columns[], int max)
{
    int num = 0;
    int ch;

    //獲取列標號
    // 判斷列標以及列標數目是否滿足條件
    // 負數,意味着列標錄入結束
    while(num < max && scanf("%d", &columns[num]) && columns[num] >= 0) 
    {
        num += 1;  // 準備下一個列標的存取和檢測
    }

    // 驗證列標數目是否爲偶數——輸入的有效列標應該是一一對應的
    if(num % 2 != 0)
    {
        puts("Last column number is not paired.");
        exit(EXIT_FAILURE);
    }

    // 丟棄最後一個數字之後的部分——截至輸入的回車(或文件結尾)之間的空白
    // 比如: 0 2 4 6 -1      'EOF'或者'\n'
    while( (ch = getchar()) != EOF && ch != '\n')
    {
        ;
    }

    return num;  // 返回擁有的列標總數
}


// 實現字符串的列標截取
void rearrange(char *output, char const *input,
            int n_columns, int const columns[])
{
    int col;  // 列標索引
    int output_col;  // 輸出行列標索引——即存儲開始索引
    int len;  // 輸入字符串長度
    int nchars;  // 每次允許的拼接字符長度

    len = strlen(input);
    output_col = 0;  // 初始爲0
    nchars = 0;

    for(col = 0; col < n_columns; col += 2)  // 每兩個列標進行一次操作
    {
        nchars = columns[col+1] - columns[col] + 1;  // 獲取兩個列標之間的差——即截取字符個數
		// 判斷列標是否超過輸入行字符串長度
		// 輸出行的索引不大於最大索引:MAX_INPUT - 1
        if(columns[col] >= len || output_col == MAX_INPUT - 1)   
        {
            break;
        }
        if(output_col + nchars > MAX_INPUT - 1)  // 如果截取字符個數加上輸出行索引超過最大索引時,進行截取重計算
        {
            nchars = MAX_INPUT - output_col - 1;
        }
        strncpy(output + output_col, input + columns[col], nchars);  // 通過複製來截取
        output_col += nchars; // 截取後,索引按截取複製的字符數增加——0+7->7,這意味着下一次拼接從7開始(7爲拼接位)
    }
    output[output_col] = '\0';  // 給字符串拼接位加上結束字符NUL,n索引下賦值'\0'
}

測試樣例:(免得再麻煩,可以使用這個來測試程序)

4 9 12 20 -1
abcdefghijklmnopqrstuvwxyz
Hellow there, how are you?
I am fine, thanks.
See, you!
Bye!

效果

在這裏插入圖片描述

問題思考

  1. 如果輸入一對列標,不是遞增時,該如何處理?
    if(columns[col] >= len || output_col == MAX_INPUT - 1)
  2. 如果允許輸入單個有效列標位於列標輸入行的末尾,意爲從列標序號開始到字符串末尾,那程序該如何修改? if(num % 2 != 0)…

這些問題將在下一篇中用代碼展示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章