UVa OJ 123

题目描述:给出一串“可忽略关键词”(如of、and、the等)和一串“标题”(如The Old Man And The Sea等),两者用“::”分隔。任务是输出一列标题。具体要求是:所有标题中出现的“可忽略关键词”之外的单词都是“关键词”,输出的标题需按关键词的字典序排列,如果有多个标题使用同一关键词,则按标题出现的顺序依次打印。除此之外,还要求打印出的标题除了关键词大写外,其他均小写。

如:

the old MAN and the sea

the friendship between a MAN and a dog

travel to the MOON

TRAVEL to the moon

关键的知识点:字符大小写转换函数toupper和tolower;判断字母函数isalpha;sscanf中%n的用法;strcpy和strcmp函数的反复使用;给字符串排序的qsort函数。

解题思路:首先要读入“可忽略关键词”,保存在数组ignore中,然后读入“标题”,保存在title中。(注意用全局变量,否则可能空间不够!)

并且,读入“可忽略关键词”之后应该用一个getchar()消去多余的回车,否则fgets会仅仅读入一个回车。

我们选择一个一个处理字符。用sscanf时需要使用格式符%n来帮助确定指针,读入后存在数组s中,(注意s在本题中要及时清零)顺便统一转小写。若遇空格或回车,首先判断s是否是“可忽略关键词”,方法比较原始,只能逐个比较。若是,则令flag=0,清空s,continue;若不是,则与sort中已有的单词比较,若有相同的,则在num数组中保存句子序号、单词在句子中开始的序号、单词在句子中结束的序号三个信息。其中num【k】【0】保存数组长度,若没有相同的,则将单词加入sort,这里不再赘述。处理完后将sort整体复制到sorted,调用qsort函数,将字符串排为字典序。然后将sorted从上到下进行检索,目的是在sort中找出与之相同的单词,然后可以找到对应的num(序号相同),由于保存时就是按句子顺序排列的,所以也顺便符合题目中“多个标题使用同一关键词”的要求。打印时,判断“指针”p是否落在关键词的区间里,若是,则输出大写,若不是,则输出小写。不用添加printf("\n"),因为在fgets读入的时候,已经读入了回车符。

具体程序如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char s[15]="",ignore[55][15]={""},sort[3000][15]={""},sorted[3000][15]={""},title [210][310]={""};
int num[3000][630]={0};
int cmp_string(const void*_a,const void*_b);
int main(void)
{
    int i=0,j=0,k=0,ignum=0,tinum=0,n=0,ch=0;
    for(i=0;i<3000;i++)
         num[i][0]=1;
    i=0;
    while(scanf("%s",s)==1&&isalpha(s[0]))
        {
           strcpy(ignore[i++],s);
           memset(s,'\0',sizeof(s));
        }
    getchar();
    while(fgets(title[j],310,stdin)!=NULL)
          j++;
    ignum=i;tinum=j;
    memset(s,'\0',sizeof(s));
    for(j=0;j<tinum;j++)
    {
        char *p=title[j];
        int count=-1,temp,q=0;
        while(sscanf(p,"%c%n",&ch,&n)==1)
        {
            count++;
            p+=n;
            if(isalpha(ch)) s[q++]=tolower(ch);
            if(ch==' '||ch=='\n')
            {
                int flag=1,judge=1,len=q;
                q=0;
                for(i=0;i<ignum;i++)
                if(strcmp(ignore[i],s)==0) {flag=0;break;}
                if(!flag) {memset(s,'\0',sizeof(s));continue;}
                for(i=0;i<k;i++)
                  if(strcmp(sort[i],s)==0)
                      {
                          temp=num[i][0];
                          num[i][temp]=j;
                          num[i][temp+1]=count-len;
                          num[i][temp+2]=count-1;
                          num[i][0]+=3;
                          judge=0;
                          break;
                      }
                if(judge)
                  {
                     temp=num[k][0];
                     num[k][temp]=j;
                     num[k][temp+1]=count-len;
                     num[k][temp+2]=count-1;
                     num[k][0]+=3;
                     strcpy(sort[k++],s);
                  }
                 memset(s,'\0',sizeof(s));
            }
            if(ch=='\n') break;
        }
    }
    for(i=0;i<k;i++)
        strcpy(sorted[i],sort[i]);
    qsort(sorted,k,sizeof(sorted[0]),cmp_string);
    for(i=0;i<k;i++)
      for(j=0;j<k;j++)
         if(strcmp(sorted[i],sort[j])==0)
         {
             int t=1;
             while(t<num[j][0])
             {
                 int p=0;
                while(title[num[j][t]][p]!='\0')
                {
                   if(p>=num[j][t+1]&&p<=num[j][t+2])
                        printf("%c",toupper(title[num[j][t]][p]));
                   else
                        printf("%c",tolower(title[num[j][t]][p]));
                 p++;
                }
                t+=3;
             }
         }
     return 0;
}
int cmp_string(const void*_a,const void*_b)
{
    char*a=(char*)_a;
    char*b=(char*)_b;
    return strcmp(a,b);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值