SQL注释:
1.单行注释:--单行注释
2.多行注释:/*多行
注释*/
1.用 字节数组 实现“跳过”注释
非常感谢我的良师益友@Caodenk提供了破题思路(字节数组就真的很香哇)~然后某陌补充了一丢丢,最后整理如下。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
namespace Test
{
public partial class skip : Component
{
public class Skip
{
public static (byte[], int) RemoveComment(byte[] sqlBuf, int Length)
{
byte[] retBuf = new byte[Length];
int j = 0;
for (int i = 0; i < Length;)
{
if (sqlBuf[i] == '/' && sqlBuf[i + 1] == '*') //多行注释
{
i += 2;
SkipComment(ref i, sqlBuf);
}
else if (sqlBuf[i] == '-' && sqlBuf[i + 1] == '-') //单行注释
{
i += 2;
SkipComment1(ref i, sqlBuf);
}
else
{
retBuf[j] = sqlBuf[i];
++j;
++i;
}
}
return (retBuf, j);
}
public static void SkipComment(ref int i, byte[] buf)
{
for (; ; i++)
{
if (buf[i] == '*' && buf[i + 1] == '/')
{
i += 2;
break;
}
}
}
public static void SkipComment1(ref int i, byte[] buf)
{
for (; ; i++)
{
if (buf[i] == '\n' || buf[i] == '\r') //判定换行符即可
{
i += 2;
break;
}
}
}
}
}
}
使用时调用方式:
string filepath = @"TEST.sql";//原文件
string filepath2 = @"test1.sql";//过滤注释后的文件
using (var filestream = File.Open(filepath, FileMode.Open))
{
byte[] buf = new byte[1024 * 1024 * 2];
int Length = filestream.Read(buf,0,buf.Length);
(var retbuf, int len) = skip.Skip.RemoveComment(buf, Length);
using (var createfile = File.Create(filepath2))
{
createfile.Write(retbuf, 0, len);
}
}
上面的代码仅作测试Demo,这个思路差不多也可以处理大部分的基本情况了。当然,在此基础上也可以写“活”文件名称,写入完毕后也可以加入一些人性化的提示信息,等等。但是,在网上查阅资料的时候看到了一些“极端”的案例,比如:
@a varchar(10)='/*',
@b datetime='*/',
像这种情况上面的代码明显招架不住的……
另,我的良师益友后来又特别补充了一点:\r不是换行符,必须遇到\n才行(mac oc除外)在Windows中\r\n,linux时\n.故他的单行过滤是这么写的。
static void SkipSingleLineComment(ref int i,byte[] buf,int length)
{
for(;;i++)
{
if(buf[i]=='\n')
{
i++;
break;
}
if(i>=length) break;
}
}
2.正则实现过滤注释
用正则过滤sql中的注释需要注意的是,读取文件时不能选用StreamReader的ReadLine()函数(逐行读取),因为在处理单行注释时只需判断是否是“--”开头即可,但是处理多行注释时就明显不适用了。解决办法是用StreamReader的ReadToEnd()方法读完文件,所以在良师益友的帮助下又有了正则的破题之法~
string ClearMark(string input)
{
input =Regex.Replace(input, @"(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|'(?:[^']|'')*'|(--.*)","");
return input;
}
这里的@代表后面的字符串原样匹配,故不需要写\\只用写一个\,但是*在正则中表示0或多个,所以对应的注释/**/就要写成/\*,同时上面的正则也去掉了''中的内容(这里过滤掉了表里的数据,如果需要保留SP的完整性就去掉这段过滤条件)。
使用时的调用方法:
string file = @"d:/test.sql";
ReadFile(file,@"d:/test3.sql");
static void ReadFile(string file,string savepath)
{
string input=null;
using(StreamReader sr = new StreamReader(file))
{
input = sr.ReadToEnd();
input = ClearMark(input);
using(StreamWriter sw = new StreamWriter(savepath))
{
sw.Write(input);
}
}
}
最后,再次感谢我的良师益友@Caodenk~~~
参考文档: