1 单词长度(5分)
题目内容:你的程序要读入一行文本,其中以空格分隔为若干个单词,以‘.’结束。你要输出这行文本中每个单词的长度。这里的单词与语言无关,可以包括各种符号,比如“it's”算一个单词,长度为4。注意,行中可能出现连续的空格。
输入格式:输入在一行中给出一行文本,以‘.’结束,结尾的句号不能计算在最后一个单词的长度内。
输出格式:在一行中输出这行文本对应的单词的长度,每个长度之间以空格隔开,行末没有最后的空格。
输入样例:It's great to see you here.
输出样例:4 5 2 3 3 4
代码实现:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner ( System.in );
String s = in.nextLine();
// System.out.println(s);
int number = 0;
for ( int i=0 ; i<s.length() ; i++ ) {
number++;
if ( i>0 ) {
if ( s.charAt(i)==' ' ) {
if ( s.charAt(i-1)!=' ' )
System.out.print((number-1)+" ");
number = 0;
}
if ( s.charAt(i)=='.' ) {
if ( s.charAt(i-1)!=' ' )
System.out.print(number-1);
else
System.out.print("0");
}
}
}
in.close();
}
}
2 GPS数据处理(5分)
题目内容:
NMEA-0183协议是为了在不同的GPS(全球定位系统)导航设备中建立统一的BTCM(海事无线电技术委员会)标准,由美国国家海洋电子协会(NMEA-The National Marine Electronics Associa-tion)制定的一套通讯协议。GPS接收机根据NMEA-0183协议的标准规范,将位置、速度等信息通过串口传送到PC机、PDA等设备。
NMEA-0183协议是GPS接收机应当遵守的标准协议,也是目前GPS接收机上使用最广泛的协议,大多数常见的GPS接收机、GPS数据处理软件、导航软件都遵守或者至少兼容这个协议。
NMEA-0183协议定义的语句非常多,但是常用的或者说兼容性最广的语句只有$GPGGA、$GPGSA、$GPGSV、$GPRMC、$GPVTG、$GPGLL等。其中$GPRMC语句的格式如下
$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
这里整条语句是一个文本行,行中以逗号“,”隔开各个字段,每个字段的大小(长度)不一,这里的示例只是一种可能,并不能认为字段的大小就如上述例句一样。
字段0:$GPRMC,语句ID,表明该语句为Recommended Minimum Specific GPS/TRANSIT Data(RMC)推荐最小定位信息
字段1:UTC时间,hhmmss.sss格式
字段2:状态,A=定位,V=未定位
字段3:纬度ddmm.mmmm,度分格式(前导位数不足则补0)
字段4:纬度N(北纬)或S(南纬)
字段5:经度dddmm.mmmm,度分格式(前导位数不足则补0)
字段6:经度E(东经)或W(西经)
字段7:速度,节,Knots
字段8:方位角,度
字段9:UTC日期,DDMMYY格式
字段10:磁偏角,(000 - 180)度(前导位数不足则补0)
字段11:磁偏角方向,E=东W=西
字段16:校验值
这里,“*”为校验和识别符,其后面的两位数为校验和,代表了“$”和“*”之间所有字符(不包括这两个字符)的异或值的十六进制值。上面这条例句的校验和是十六进制的50,也就是十进制的80。
提示:^运算符的作用是异或。将$和*之间所有的字符做^运算(第一个字符和第二个字符异或,结果再和第三个字符异或,依此类推)之后的值对65536取余后的结果,应该和*后面的两个十六进制数字的值相等,否则的话说明这条语句在传输中发生了错误。注意这个十六进制值中是会出现A-F的大写字母的。另外,如果你需要的话,可以用Integer.parseInt(s)从String变量s中得到其所表达的整数数字;而Integer.parseInt(s, 16)从String变量s中得到其所表达的十六进制数字
现在,你的程序要读入一系列GPS输出,其中包含$GPRMC,也包含其他语句。在数据的最后,有一行单独的END表示数据的结束。
你的程序要从中找出$GPRMC语句,计算校验和,找出其中校验正确,并且字段2表示已定位的语句,从中计算出时间,换算成北京时间。一次数据中会包含多条$GPRMC语句,以最后一条语句得到的北京时间作为结果输出。
你的程序一定会读到一条有效的$GPRMC语句。
输入格式:多条GPS语句,每条均以回车换行结束。最后一行是END三个大写字母。
输出格式:6位数时间,表达为:hh:mm:ss. 其中,hh是两位数的小时,不足两位时前面补0;mm是两位数的分钟,不足两位时前面补0;ss是两位数的秒,不足两位时前面补0。
输入样例:
$GPRMC,024813.640,A,3158.4608,N,11848.3737,E,10.05,324.27,150706,,,A*50
END
输出样例:10:48:13
题目分析:
首先这题题目较长,但是题目中有效信息不多,所有有效信息,我均用蓝色字体给大家标识出来了,这题说白了就是让你判断三个事:第一,找出输入的$GPRMC语句,第二,$与*之间的字符的异或值对65586取余是否与*后面的16进制数相同;第三,第二个逗号后面的字段是不是A. 只要满足以上两点的一条数据,即为正确的数据,而这个程序可能输入多条数据,以END作为最后一条数据,但是我们只要输出之后一条合法数据中的时间对应的北京时间,即第一个逗号与第二个逗号之间的数据,只取整数部分,然后再将得到的六位整数,中的前两位加8,在做跨日计算处理,之后输出即可.
在这其中用到的新运算与字符串操作的函数列举如下:
1. 异或运算:
int m = a;
int n = b;
int c = m^n;
其中c的值为m,n两变量的异或值,也就是a,b的异或值;
2. 得到字符串中某个位置上的存储的内容:
int i = a;
char c = s.charAt(i);
其中a为我要取的内容在数组中存放的位置;
3. 截取某一字符串中的一部分,赋值给另一个新数组:
int loc_start = a;
int loc_end = b;
String s1 = new String ("abcdef");
String S2 = s1.substring(loc_start,loc_end);
其中loc_start表示需要截取的字符串s1的起始位置,loc_end表示需要截取的字符串s1的终止位置,也就是
把字符串s1的从a到b位置的内容赋值给字符数穿s2;
4. 若字符串内存储的是整数,将字符串内的整数赋值给一个整型变量:
int number = 0;
String s = new String ("123");
number = Integer.parseInt ( s,10 );
表示将获取字符串s内存储的十进制数,赋值给整型变量number.
代码实现:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner ( System.in ); //开始输入
String s = new String("");
//初始化字符串,准备读入语句
int [] time = new int [3];//定义time数组,便于存储时间
s = in.nextLine(); //读入语句
do {
boolean right = true;
//定义布尔类型变量right便于后续判断语句是否合法
//取出字段0,并判断是否是$GPRMC语句
String title = s.substring(1,6); //取出字段0,存入字符串title
if ( title.compareTo("GPRMC")!=0 )
right = false;
//比较字符串title与GPRMC是否相同,否则语句不合法,
//不参与后续时间计算,right赋为假
//判断$与*之间的异或值对65536取余是否与校验值相同
int loc_value = 0; //定义变量,以便确定校验值的位置
for ( int i=0 ; i<s.length() ; i++ ) {
if ( s.charAt(i)=='*' ) {
loc_value = i + 1;
break;
//由于*之后为校验值,故找到*即可跳出循环,得到校验值位置
}
}
//将校验值对应的两个位置内存储的两位整型变量提取到新的字符串s_value中
String s_value = s.substring(loc_value,loc_value+2);
int value = Integer.parseInt(s_value,16);
//由于校验值为16进制,故将字符串中存储的16进制数赋值给value
int test = (int)s.charAt(1); //定义变量,计算异或值
for ( int i=2 ; i<loc_value-1 ; i++ )
test = test ^ (int)s.charAt(i);
//每一轮循环让现有的异或值同下一个变量进行异或计算,得到最终异或值
if ( (test%65536)!=value )
right = false;
//判断异或值对65536取余是否与校验值相等,否则数据传输出错,
//不参与后续时间计算,right赋为假
//判断字段2处的内容是否为A
int loc_A = 0; //定义变量,以便确定字段2的位置
for ( int j=0 ; j<2 ; j++ ) {
for ( int i=loc_A ; i<s.length() ; i++ ) {
if ( s.charAt(i)==',' ) {
loc_A = i + 1;
break;
//由于字段2在第二个逗号后面,故通过两轮循环找到第二个
//逗号后跳出循环,即得到字段2的位置
}
}
}
char comp = s.charAt(loc_A); //将字段2内容存入新的char变量comp
if ( comp!='A' )
right = false;
//判断comp内内容是否为A,否则数据非法,
//不参与后续时间计算,right赋为假
//若数据合法,进行如下时间操作
if ( right ) {
int loc = 0; //定义变量,以便确定六位时间的位置
for ( int i=0 ; i<s.length() ; i++ ) {
if ( s.charAt(i)==',' ) {
loc = i + 1;
break;
//由于时间存放在第一个逗号后面,故找到第一个逗号,
//即可跳出循环,即得到六位时间的位置
}
}
//将时间的前两位取出作为time数组的第一个变量,当做小时
String time_min = s.substring(loc,loc+2);
// System.out.println(time);
time[0] = Integer.parseInt(time_min,10) + 8;
//防止出现小时数大于24的情况,便做如下时间跨日处理
if ( time[0]>=24 )
time[0] = time[0] - 24;
//分别取出时间的中间两位与后两位,分别作为数组time的
//第二三个变量,当做分钟与秒
time_min = s.substring(loc+2,loc+4);
time[1] = Integer.parseInt(time_min,10);
time_min = s.substring(loc+4,loc+6);
time[2] = Integer.parseInt(time_min,10);
}
s = in.nextLine();
//对当前语句全部处理结束,录入下一条一句
} while ( s.compareTo("END")!=0 );
//如果语句的内容为END跳出循环,即对当前语句即END不做处理
//视作数据处理结束,准备打印时间
//现在数组time内时间为最后一条合法语句的时间,打印出即可
//不满两位,即数据小于10的前面补0
if ( time[0]<10 )
System.out.print("0");
System.out.print(time[0]+":");
if ( time[1]<10 )
System.out.print("0");
System.out.print(time[1]+":");
if ( time[2]<10 )
System.out.print("0");
System.out.print(time[2]);
in.close();
//输入流结束
}
}