簡體   English   中英

Kernighan 和 Ritchie - 練習 3.3(展開函數)

[英]Kernighan and Ritchie - exercise 3.3 (expand function)

我已經解決了 K&R 書中的練習 3.3。 我實施的解決方案似乎有效,但有點冗長,可能有更聰明的方法來編寫此代碼。 我想問一下我實施的解決方案是否可能存在問題,以及是否有更簡單的編寫方法:

編寫一個函數 expand(s1,s2) 將字符串 s1 中的 az 等速記符號擴展為 s2 中等效的完整列表 abc...xyz。 允許大小寫和數字的字母,並准備處理諸如 abc 和 a-z0-9 和 -az 之類的情況。 安排前導或尾隨 - 從字面上看

我的代碼是這樣的:

#include <stdio.h>

void expand(char s1[],char s2[]){
  int j=0,i=0;
  while(s1[j] != '\0'){
    if (s1[j]>= 'a' &&  s1[j] <= 'z' && s1[j+1] == '-' && s1[j+1]!='\0' &&  s1[j+2] >= 'a' &&  s1[j+2] <= 'z' && s1[j+2] !='\0'){
      int z = s1[j+2]-s1[j];
      int c;
      for (c=0;c<=z;c++){
    s2[i]= c+s1[j];
    i++;
      }
      j=j+3;
            
    }
    else if (s1[j]>= 'A' &&  s1[j] <= 'Z' && s1[j+1] == '-' && s1[j+1]!='\0' &&  s1[j+2] >= 'A' &&  s1[j+2] <= 'Z' && s1[j+2] !='\0'){
      int z = s1[j+2]-s1[j];
      int c;
      for (c=0;c<=z;c++){
    s2[i]= c+s1[j];
    i++;
      }
      j=j+3;
            
    }
    else if (s1[j]>= '0' &&  s1[j] <= '9' && s1[j+1] == '-' && s1[j+1]!='\0' &&  s1[j+2] >= '0' &&  s1[j+2] <= '9' && s1[j+2] !='\0'){
      int z = s1[j+2]-s1[j];
      int c;
      for (c=0;c<=z;c++){
    s2[i]= c+s1[j];
    i++;
      }
      j=j+3;
            
    }
    else  if (j!= 0  && s1[j] == '-'  && (s1[j-1] < s1[j+1])){
      int z = s1[j+1]-(1+s1[j-1]);
      int c;
      for (c=0;c<=z;c++){
    s2[i]= c+(s1[j-1]+1);
    i++;
      }
      j=j+2;
      
    }      
    else if ( s1[j]>= 32 &&  s1[j] <= 127 && (s1[j+1] != '-' || s1[j+1]>= 32 &&  s1[j+1] <= 127 )){
      s2[i] = s1[j];
      
      j++;
      i++;      
     }
  }
  s2[i]='\n';
  i++;
  s2[i]='\0';
}


int main() {

  int c;
  char s2[100];
  expand("-a-c,a-c-g,A-Z0-9--", s2);
  
  printf("%s",s2);
 
 
}

代碼以這種方式工作:

首先,它檢查是否存在“xy”類型的三元組,其中 x<y。 然后,如果將包含從 x 到 y 的值提供給數組,並跳轉到三元組“xy”之后的下一個字符。 對於大寫字母和進一步 if 條件中的數字也是如此。

條件else if (j!= 0 && s1[j] == '-' && (s1[j-1] < s1[j+1]))用於檢查像“ac-d1”這樣的情況。 我在這個例子中實現的代碼將這樣工作:因為我們從“acd”中的第 0 個字符開始,並且存在模式“xy”,“abc”將被分配給數組。 然后我們將直接跳轉到第二個 - 在“acf”中。 由於這第二個 - 前面是字母“c”,后跟字母“f”,並且“c”<“f”,那么“c”和“f”之間的字符將被分配給數組,不包括首字母“c”。 然后字符串的索引將跳躍 2 並達到 1。

其他一些方式:

  • 您只知道之前的最后一個字符 - 以及它是否與當前字符類型相同(小寫或大寫字母或數字)

  • 當你得到一個 - 並且前一個字符是一個字母或數字時,你知道你可能需要進行擴展

  • 如果后面有一個字母或數字 - 並且它對應於之前的字母/數字 - 你知道你可以從 / 之前的字符擴展到當前字符。

  • 您確實需要向前看,但只保存之前的字符和字符 -

  • 您對每種不同的字符類型(字母/數字)進行相同類型的處理,您可以在以下位置找到示例:

    #include <stdio.h> // 處理不同的字符類型 typedef enum E_chartype { LowerCaseLetter, UpperCaseLetter, Digit09, OtherChar } E_chartype;

    // 保存是否有可能的擴展 typedef enum E_states { NothingStarted, StartedExpansion } E_states;

    // 查找字符類型 E_chartype getCharType(char c) { if ((c >= 'a') && (c <= 'z')) return LowerCaseLetter;

     if (( c >= 'A') && (c <= 'Z')) return UpperCaseLetter; if ((c >= '0') && (c <= '9')) return Digit09; return OtherChar;

    }

    void expandopt(char *inS, char *outS) { // 初始化輸出字符串為空字符串 outS[0] = 0; char *endS = outS; E_states automat = NothingStarted; 字符已保存字符 = 0; int currentIndex; E_chartype prevCType=OtherChar,savedCType=OtherChar; 字符已保存C = 0,prevC=0;

     // loop on input string for (currentIndex = 0; inS[currentIndex] != 0;currentIndex++) { // save current char in variable c for shorter writting char c = inS[currentIndex]; printf("%c : ",c);

    // 保存當前字符的類型 E_chartype currentCType = getCharType(c);

    switch (automat) { // 一般情況尚未開始 case NothingStarted: // 如果前一個 chsr 是字母或數字並且當前字符是 - if ((prevCType != OtherChar) && (c == '-')) { printf("開始代表\\n"); 自動 = 開始擴展; // 保存前一個字符和它的類型,因為它是引用 fircexpansion savedCType = prevCType; 保存 C = 上一個; } else { // 將當前字符重置並cooy 到iutput automat = NothingStarted; printf("什么都沒有\\n");

     *endS++ = c; } break; case StartedExpansion: // we make ecpansion only if still same char type and letter/digit is strictly after saved one

    if ((currentCType == savedCType) && (c > savedC)){ printf("expansion "); for (char newC = savedC+1;newC <= c;newC++) { *endS++ = newC; }

     // save char in case thrre id a - after, which mean nee expansion savedC = c; } else { // save current chsrcsnd its type savedCType = currentCType; savedC = c; // copy previous char (= -) whch was not vopief in case of expansion *endS++ = prevC; *endS++ = c; }

    自動 = 沒有開始; 休息; }

     // save current chsr and type prevCType = currentCType; prevC = c; }

    // 在字符串末尾添加 0 *endS = 0; }

    int main() { expandopt("-ac,acg,A-Z0-9–",s2); printf("%s\\n",s2); }

抱歉代碼格式,我在手機上沒有找到好的代碼編輯器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM