一个公司的上机面试题。
有一个c语言写的简单代码文件input.c,要求写一个java程序,读取input.c文件的内容然后去掉注释,包括\\和\**\,注意不能删除引号里边的注释,然后保存到output.c文件。
input.c文件如下:
#include<iostream.h> struct a { char a /*2392839238923 /*kasdlfj*/asld*/; char b; //23232392839 }; /* askdashfla' asdfalskdfhlksafdhla fasdjfhalsdjfhlasdf askjdfhlkajds * / */ void Function(int param /*232323* / */) { //*2323234234l int i = 1;//2923939 char str[] = "/*232323"; int j = 0; i = i / j * i; strcpy(str, "/*lakjslkdflksd*/"); } main() { }
用正则表达式解决如下:
public class CommentTest extends TestCase{ @Test public void testDeleteComent(){ BufferedReader reader = null; PrintWriter writer = null; try { reader = new BufferedReader(new FileReader("c:/input.c")); writer = new PrintWriter("c:/output.c"); Map<String, String> map = new HashMap<String, String>(); Pattern pattern = null; String line = ""; StringBuffer content = new StringBuffer(); pattern = Pattern.compile("\".*?\"");//引号 while((line=reader.readLine())!=null){ StringBuffer sb = new StringBuffer(); Matcher matcher = pattern.matcher(line); //找到引号,用唯一标识符替换掉引号及其内容,并且保存在map中 while(matcher.find()){ String key = UUID.randomUUID().toString().toUpperCase(); map.put(key, matcher.group()); matcher.appendReplacement(sb, key);//逐一替换 } matcher.appendTail(sb); //替换一行中的//和/**/注释 line = sb.toString().replaceAll("/\\*.*\\*/|//.*", ""); if (!line.isEmpty()){ content.append(line).append("\n"); } } //替换跨行的/**/注释 (?s)为启用 dotall 模式,把换行符\n也一块删掉 String result = content.toString().replaceAll("(?s)/\\*.*\\*/", ""); //还原引号及其内容 for(Map.Entry<String, String> entry:map.entrySet()){ result = result.replace(entry.getKey(), entry.getValue()); } writer.println(result);//写入新的文件中 writer.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ try { if (null != reader) reader.close(); if (null != writer) writer.close(); } catch (IOException e) { } } } }
输入结果out.c
#include<iostream.h> struct a { char a ; char b; }; void Function(int param ) { int i = 1; char str[] = "/*232323"; int j = 0; i = i / j * i; strcpy(str, "/*lakjslkdflksd*/"); } main() { }
最近在看Matcher的源码,以下的替换方法与Matcher.replaceAll方法很相似,看来多看点源码还是很有用的。
//找到引号,用唯一标识符替换掉引号及其内容,并且保存在map中 while(matcher.find()){ String key = UUID.randomUUID().toString().toUpperCase(); map.put(key, matcher.group()); matcher.appendReplacement(sb, key);//逐一替换 } matcher.appendTail(sb);
其中Matcher.replaceAll方法的源码如下
public String replaceAll(String replacement) { reset(); boolean result = find(); if (result) { StringBuffer sb = new StringBuffer(); do { appendReplacement(sb, replacement); result = find(); } while (result); appendTail(sb); return sb.toString(); } return text.toString(); }