IPv6

题目描述:

  互联网协议第六版 (IPv6) 是被设计用于替代 IPv4 的新一代互联网协议。相比 IPv4,IPv6 最大的特点是,IPv6 大幅扩大了地址空间,能够有效解决 IPv4 地址紧张的情况。  

  IPv6 地址由 128 位二进制数构成,这 128 位二进制数被分成 8 组,每组 16 位。用冒号 分隔法表示 IPv6 地址的方式如下:   

  xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx  

  其中,xxxx 是 4 位十六进制数,代表地址中一组,其中十六进制数中的字母既可以大写 也可以小写。此外,如果某组十六进制数中有多余的前导 0,那么这些多余的前导 0 可以省 略不写。例如,以下是一个 IPv6 地址的示例:  

  abcd:1234:aCA9:123:4567:089:0:0000  

  为了进一步简化书写,有时还会采用 0 位压缩表示法,即如果有一个或多个连续的全 0 组,那么可以将这些连续的全 0 组删去,替换成两个冒号 ‘::’;如果替换的结果中含有多于两 个连续冒号,则将多余的冒号删去直至只有两个连续的冒号。需要注意的是,在同一个 IPv6 地址中,0 位压缩表示最多只能使用 1 次。例如,以下均为合法的带 0 位压缩表示的 IPv6 地 址:   

  7abc::00ff:fffc 表示 7abc:0:0:0:0:0:ff:fffc 

  FC::8976:0000:0000:0000:00ff 表示 fc:0:0:8976:0:0:0:ff 

  2c0f:9981:: 表示 2c0f:9981:0:0:0:0:0:0 

  :: 表示 0:0:0:0:0:0:0:0   

  现在,给你一些可能带 0 位压缩表示的 IPv6 地址,你需要将他们转换成完整形式。具体 地说,你需要依次完成以下任务:  

  1. 恢复被压缩的全 0 组; 

  2. 补齐被省略的前导 0,直至每组都是 4 位十六进制数; 

  3. 将所有英文字母转换为小写字母。 例如,上面提到的 5 个 IPv6 地址,它们对应的完整表示分别为  

  abcd:1234:aca9:0123:4567:0089:0000:0000  

  7abc:0000:0000:0000:0000:0000:00ff:fffc  

  00fc:0000:0000:8976:0000:0000:0000:00ff  

  2c0f:9981:0000:0000:0000:0000:0000:0000  

  0000:0000:0000:0000:0000:0000:0000:0000  

 

输入描述:

第一行包含一个整数 T (1 ≤ T ≤ 200),表示测试用例的组数。
接下来 T 行,每行一个字符串,表示一个可能带 0 位压缩表示的 IPv6 地址。
保证输入一定是合法的可能带 0 位压缩表示的 IPv6 地址。

输出描述:

依次输出每个 IPv6 地址对应的完整表示。每个地址占一行。

样例输入:

5
abcd:1234:aCA9:123:4567:089:0:0000
7abc::00ff:fffc
FC::8976:0000:0000:0000:00ff
2c0f:9981::
::

样例输出:

abcd:1234:aca9:0123:4567:0089:0000:0000
7abc:0000:0000:0000:0000:0000:00ff:fffc
00fc:0000:0000:8976:0000:0000:0000:00ff
2c0f:9981:0000:0000:0000:0000:0000:0000
0000:0000:0000:0000:0000:0000:0000:0000

 

 

 

 

模拟题,但是由于代码能力不够强,这道题写了很久。

我是把整个数据分成五部分:

第一部分是开头的四个拘束的输出

第二部分是第一个:到::数据的输出

第三部分是::数据的输出

第四部分是::到最后一个:数据的输出

第五部分是最后四个数据的输出

下面附上一个通过样例的代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<stdio.h>
using namespace std;
char a[60];

int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%s",a);
        int l=strlen(a);
        int begin_number=l;
        int nod=0;
        int first_nod=-1;
        int number=0;
        for(int i=0;i<l;++i)
        {
              if(a[i]==':') nod++;   //记录:的数量
              if(a[i+1]==':') begin_number=i+1;  //记录::出现的位置
              if(a[i]==':'&&first_nod==-1)
                    first_nod=i;   //记录:第一次出现的位置
        }
        int zero=8-nod;//  代表::中间补0的数量
        for(int i=0;i<4-first_nod;++i)
            printf("0");
        for(int i=0;i<first_nod;++i)
        {
            if(a[i]>='A'&&a[i]<='Z')
                printf("%c",a[i]+32);
            else
                printf("%c",a[i]);
        }   //这里输出的是第一个:前面的内容
        for(int i=first_nod;i<begin_number;++i)
        {
            /*
            这里有考虑两种情况,有::和没有::
            如果有::需要补0,反之不需要补0
            前者的判断只需证明a[i+1]是否等于':'即可
            */
            printf(":");//先输出最左边的,然后以:为结点输出
            if(a[i+1]==':')//::的情况
            {
                number++;
                for(int k=0;k<zero;++k)
                {
                    printf("0000");
                    if(k!=zero-1)
                        printf(":");
                }
                if(number==nod-1)//如果::出现在最后边,那么要判断::后面的元素,然后输出
                {
                    printf(":");
                    for(int k=0;k<6-l+i;++k)
                        printf("0");
                    for(int k=0;k<l-i-1;++k)
                        if(a[i+k+2]>='A'&&a[i+k+2]<='Z')
                        printf("%c",a[i+k+2]+32);
                    else
                        printf("%c",a[i+k+2]);
                }//补完0之后判断这个:是否是最后一个,如果是的话,输出最后一个:后面的内容
                continue;

            }
            /*
            这里的begin_number明明是第一个::出现的位置,可是现在整个for循环的范围却是begin_number;
            但是仔细想想,不难想到,排除第一种情况后,剩下的就是没有::,在前面我们给begin_number赋
            的初值是l,那么就说得通了
            */
            for(int j=i+1;j<l;++j)
            {

                if(a[j]==':')
                {
                    number++;
                    int ll=j-i;
                    for(int k=0;k<5-ll;++k)
                        printf("0");
                    for(int k=0;k<ll-1;++k)
                        {
                            if(a[i+k+1]>='A'&&a[i+k+1]<='Z')
                            printf("%c",a[i+k+1]+32);
                            else
                            printf("%c",a[i+k+1]);
                        }
                        i=j-1;
                        break;
                }
            }
            if(number==nod-1)
            {
                i++;
                printf(":");
                for(int k=0;k<5-(l-i);++k)
                    printf("0");
                for(int k=0;k<l-i-1;++k)
                if(a[i+k+1]>='A'&&a[i+k+1]<='Z')
                    printf("%c",a[i+k+1]+32);
                else
                    printf("%c",a[i+k+1]);
                break;
            }
        }
        printf("\n");
    }
    return 0;
}

/*
5
abcd:1234:aCA9:123:4567:089:0:0000
7abc::00ff:fffc
FC::8976:0000:0000:0000:00ff
2c0f:9981::
::

abcd:1234:aca9:0123:4567:0089:0000:0000
7abc:0000:0000:0000:0000:0000:00ff:fffc
00fc:0000:0000:8976:0000:0000:0000:00ff
2c0f:9981:0000:0000:0000:0000:0000:0000
0000:0000:0000:0000:0000:0000:0000:0000


5
asd:asd:asd:asg:asfg:ef:asf:sf
5
asd:asd::asd:asd

*/

这个代码能通过90+%的测试数据,但是在中间有几十个数据是错误的:

 

后来发现是有一个地方我在写代码的时候出现了一个失误

这里在标记::位置的时候并没有判断a[i]是否为:,这样就出现了一个BUG,可竟然 通过了那么多样例~~~~~

修改后如下:

这样的话按照原来的思路,就会发现输出数据少了很多。

(原来的思路:这里有考虑两种情况,有::和没有::,如果有::需要补0,反之不需要补0,前者的判断只需证明a[i+1]是否等于':'即可。)

在排出前面判断::位置的BUG之后,很显然,这个想法不是很完善,::后面的那一部分没有输出

这个时候就要分两部分输出

1、::到最后一个:

2、最后一个:后面的内容

 

AC代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<iostream>
using namespace std;
char a[60];
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        scanf("%s",a);
        int l=strlen(a);
        int begin_number=l;
        int nod=0;
        int first_nod=-1;
        int end_nod=-1;
        int number=0;
        for(int i=0; i<l; ++i)
        {
            if(a[i]==':')
            {
                nod++;    //记录:的数量
                end_nod=i;
            }
            if(a[i]==':'&&a[i+1]==':')
                begin_number=i;  //记录::出现的位置
            if(a[i]==':'&&first_nod==-1)
                first_nod=i;   //记录:第一次出现的位置
        }
        int zero=8-nod;//  代表::中间补0的数量
        for(int i=0; i<4-first_nod; ++i)
            printf("0");
        for(int i=0; i<first_nod; ++i)
        {
            if(a[i]>='A'&&a[i]<='Z')
                printf("%c",a[i]+32);
            else
                printf("%c",a[i]);
        }

        for(int i=first_nod; i<begin_number; ++i)
        {
            printf(":");
            if(a[i+1]==':')
            {
                number++;
                for(int k=0; k<zero; ++k)
                {
                    printf("0000");
                    if(k!=zero-1)
                        printf(":");
                }
                if(number==nod-1)
                {
                    printf(":");
                    for(int k=0; k<6-l+i; ++k)
                        printf("0");
                    for(int k=0; k<l-i-1; ++k)
                        if(a[i+k+2]>='A'&&a[i+k+2]<='Z')
                            printf("%c",a[i+k+2]+32);
                        else
                            printf("%c",a[i+k+2]);
                }//补完0之后判断这个:是否是最后一个,如果是的话,输出最后一个:后面的内容
                continue;

            }
            for(int j=i+1; j<l; ++j)
            {

                if(a[j]==':')
                {
                    number++;
                    int ll=j-i;
                    for(int k=0; k<5-ll; ++k)
                        printf("0");
                    for(int k=0; k<ll-1; ++k)
                    {
                        if(a[i+k+1]>='A'&&a[i+k+1]<='Z')
                            printf("%c",a[i+k+1]+32);
                        else
                            printf("%c",a[i+k+1]);
                    }
                    i=j-1;
                    break;
                }
            }
            if(number==nod-1)
            {
                i++;
                printf(":");
                for(int k=0; k<5-(l-i); ++k)
                    printf("0");
                for(int k=0; k<l-i-1; ++k)
                    if(a[i+k+1]>='A'&&a[i+k+1]<='Z')
                        printf("%c",a[i+k+1]+32);
                    else
                        printf("%c",a[i+k+1]);
                break;
            }
        }
        if(begin_number!=l)
        {
            for(int i=0; i<zero; ++i)
            {
                printf(":0000");
            }
            for(int i=begin_number+1; i<=end_nod; ++i)
            {
                int judge=i;
                printf(":");
                for(int j=i+1; j<=end_nod; ++j)
                {
                    if(a[j]==':')
                    {
                        for(int k=0; k<5-(j-i); ++k)
                            printf("0");
                        for(int k=0; k<j-i-1; ++k)
                            {
                                if(a[i+k+1]>='A'&&a[i+k+1]<='Z')
                                printf("%c",a[i+k+1]+32);
                                else
                                printf("%c",a[i+k+1]);
                            }
                        i=j-1;
                        break;
                    }
                }
                if(i==judge)
                    break;
            }
        }
        if(begin_number!=l)
        {
            for(int i=0; i<5-(l-end_nod); ++i)
                printf("0");
            for(int i=0; i<l-end_nod-1; ++i)
            {
                if(a[end_nod+i+1]>='A'&&a[end_nod+i+1]<='Z')
                    printf("%c",a[end_nod+i+1]+32);
                else
                    printf("%c",a[end_nod+1+i]);
            }
        }
        if(n!=0)
            printf("\n");
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值