分类: LINUX
2017-10-16 11:02:03
其实这个内容应该更准确的界定为bash环境下非英文字符的处理,但由于我们主要涉及的是中文,或者中英混合文字的处理,所以本文以此为题。
这个问题产生的背景是在处理混合了中英文字符(含标点符号)的内容,用于生成某背景下的图片时,因 为英文字符(含标点,下同)只占1个字符位宽,中文字符(含全角标点)则占2个字符位宽,为了好看,需要精确计数各种字符数量,所以产生了本问题。
通过2次替换过滤,产生2种输出,分别是中文字符串和英文字符串,分别计数。 拟处理的字符串为 ASTRING,例如
ASTRING="1一2二a三B四-五:六 七\""
则输出中文字符串为
CSTRING=$( echo ${ASTRING} | sed -n "s/[[:lower:][:upper:][:digit:][:blank:][:punct:]]//gp" )
CSTRING中则是所有的中文字符,
则输出英文字符串为
BSTRING=$( echo ${ASTRING} | sed -n "s/[^[:lower:][:upper:][:digit:][:blank:][:punct:]]//gp" )
BSTRING中则是所有的英文字符,
但这样处理在纯中文或者纯英文的字符串时都会出错(BSTRING和CSTRING均为空),所以需要进行前置检测。
检测方法是,运行
TEST1=$( echo ${ASTRING} | grep -e "[^[:lower:][:upper:][:digit:][:blank:][:punct:]]" ) TEST2=$( echo ${ASTRING} | grep -e "[[:lower:][:upper:][:digit:][:blank:][:punct:]]" )
则此包含中文时TEST1非空,包含英文时TEST2非空。
这样结合前面的内容就可以较完备的检测处理中文了。
前面规则式中用到了[:XXXX:]一样的形式,这称为posix字符类,一共有
字符 | 描述 | 扩展意义(等效) |
---|---|---|
[:alnum:] | 字母与数字字符 | [0-9a-zA-Z] |
[:digit:] | 数字字符 | [a-zA-Z] |
[:alpha:] | 字母字符 | [a-zA-Z] |
[:blank:] | 空格与制表符 | [ \t] |
[:cntrl:] | 控制字符 | [\x01-\x1F] |
[:graph:] | 可打印与可见字符 | [^\x01-\x20] |
[:lower:] | 小写字符 | [a-z] |
[:upper:] | 大写字符 | [A-Z] |
[:print:] | 可打印字符 | [\t\x20-\xFF] |
[:punct:] | 标点字符 | [-!"#$%&'( )*+,./:;<=>?@[\\\]^_'{|}~] |
[:space:] | 空白字符如空格符、制表符、回车符、换行符、垂直制表符以及换页符 | [ \t\r\n\v\f] |
[:xdigit:] | 用于表示十六进制的字符;在ASCII中,与[0-9A-Fa-f]等效 | [0-9A-Fa-f] |
[:graph:] | 同[:print:],但不包括空格 | [\t\x21-\xFF] |
注表内扩展意义中的\xXX等仅仅表示十六进制编码值,在bash下sed与ed规则式中并不起效(它们仅支持 BASIC REGULAR EXPRESSIONS ———— BRE,基本规则式语法),测试了grep支持,所以必要时字符处理需要采用sed、ed之外的工具,以获得更多便利。
根据这个列表上前面的规则式中[:lower:][:upper:][:digit:]部分理论上可以用[:alnum:]代替,但测试这样是不行的,起码在我的环境
LANG="zh_CN.UTF-8" LANGUAGE="zh_CN:zh"
下是不行的,测试出[:alnum:]实际上包括了所有的可见字符。
对字符串中字符计数有多种方法,主要是:
echo ${#ASTRING}
echo ${ASTRING} | wc -c
不过这个只能对英文字符串正确计数,对中文字符串则不对,甚至不同环境计数也不统一。要兼容需要用
echo ${ASTRING} | wc -m
即使这样,你会发型其与用第1种方法计数的结果还有差异,相差1个字符数,这是因为echo输出默认带换行,这个符号也被计数,所以更准确的处理是
echo -n ${ASTRING} | wc -m
这样就和第1种方法得出的结果一致了。