通过正则为XML过滤非法字符

1,642 阅读3分钟

最近项目中遇到一个跟xml非法字符有关的bug,于是了解了一下相关内容,在前端对xml非法字符进行过滤,以便前端能做更多的事情。先了解一下几个概念。

什么是XML

xml(eXtensible Markup Language)是被设计出来传输和存储数据的语言,它的结构和html很像,而html的用途是显示数据。我们可以在一些ajax请求的form data中看到类似的内容:

<!--demo来着菜鸟教程-->
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book category="CHILDREN">
        <title>Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
    </book>
    <book category="WEB">
        <title>Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
    </book>
</bookstore>

这个就是xml,他就是以这种方式来传递数据。第一行为声明,表明xml版本和编码。xml可以使用任何名词作为它的元素名,但是越简洁越好,避免在名称中使用“-”,“.”,“:”。可以通过元素内容或属性来携带信息。

ASCII码

定义了英语字符和二进制之间的关系,用一个字节(8位)表示一个字符。一共表示128个字符,其中还包括32个不能打印的控制符号。并且只占用一个字节的后面7位,第一位为0。ASCII表对应维基百科ASCII table

unicode码

ASCII表只能表示有限的字符,而unicode则是一个更广的字符集,码点范围从U+0000一直到U+10FFFF。几乎包括了所有的字符。然后关于unicode码的存储方式有多种,比如utf-8,utf-16,utf-32等编码方式,他们规定了怎么存储和解析unicode符号。

JavaScript对unicode的表示

在javascript中可以使用unicode表示字符。在es6之前,可以使用\uxxxx的方式来表示\u0000~uffff之间的符号。超过这个范围的就要使用两个双字节来表示。而es6之后,可以通过一个大括号来表示任何的unicode符号。比如 \u{23333}

console.log('\u0061')
// a
console.log('\u{61}')
// a

并且es6还实现了正则表达式对u修饰符的支持,含义为Unicode模式,可以直接匹配大于\ufff的字符。

sWords = sWords.replace(/\u{23333}/u,"")

解决问题

了解了这些东西之后就可以对我们的xml进行非法字符的过滤了。首先我们查看一下xml1.0版本(目前针对1.0)的字符范围

#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

那么不在这个范围里面的属于xml非法字符了,而且这么巧,大于uffff的符号都支持,然后不支持的符号我们可以通过正则去把他们过滤掉:

sXml = sXml.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\ud800-\udfff\ufffe\uffff]/g, "")

这样我们就把xml1.0不支持的符号过滤掉了。其他版本同理。

参考文章: 字符编码笔记:ASCII,Unicode 和 UTF-8

es6正则的扩展 阮一峰