源码(七) - ParameterParser

一.概述

ParameterParser类是一个简单的解析器,解析出键值对

二.源码

package org.apache.commons.fileupload;

import java.util.HashMap;
import java.util.Map;

/**
 * 一个简单的解析器,旨在解析名称/值对序列
 *  如果参数值包含不安全字符(例如'='字符或分隔符),则它们将被包含在引号中。 参数值是可选的,可以省略
 * <p>
 *  <code>param1 = value; param2 = "anything goes; really"; param3</code>
 * </p>
 */
public class ParameterParser {
    // 被解析的字符串
    private char[] chars = null;

    // 字符串的当前位置
    private int pos = 0;

    // 字符串的最大位置position
    private int len = 0;

    // 开始
    private int i1 = 0;

    // 结尾
    private int i2 = 0;

	// Map中存储的名称是否应转换为小写
    private boolean lowerCaseNames = false;

    public ParameterParser() {
        super();
    }
	
    /**
	 * 从给定的字符串中提取名称/值对的映射。 名称name预计将是独一无二的。
     * @param str 包含名称/值对序列的字符串
     * @param separators 名称/值对的分隔符
     * @return 返回一个名称/值对的Map
     */
    public Map parse(final String str, char[] separators) {
        if (separators == null || separators.length == 0) {
            return new HashMap();
        }
        char separator = separators[0];
        if (str != null) {
            int idx = str.length();
            for (int i = 0;  i < separators.length;  i++) {
                int tmp = str.indexOf(separators[i]);
                if (tmp != -1) {
                    if (tmp < idx) {
                        idx = tmp;
                        separator = separators[i];
                    }
                }
            }
        }
        return parse(str, separator);
    }

    /**
     * 从给定的字符串中提取名称/值对的映射。 名称name预计将是独一无二的。
     * @param str 包含名称/值对序列的字符串
     * @param separator 名称/值对的分隔符
     * @return 返回一个名称/值对的Map
     */
    public Map parse(final String str, char separator) {
        if (str == null) {
            return new HashMap();
        }
        return parse(str.toCharArray(), separator);
    }
	
    public Map parse(final char[] chars, char separator) {
        if (chars == null) {
            return new HashMap();
        }
        return parse(chars, 0, chars.length, separator);
    }

    /**
     * 从给定的字符串中提取名称/值对的映射。 名称name预计将是独一无二的。
     *
     * @param chars 包含名称/值对序列的字符数组
     * @param offset - 初始偏移量
     * @param length - 长度
     * @param separator 名称/值对的分隔符
     * @return 返回一个名称/值对的Map
     */
    public Map parse(final char[] chars, int offset, int length, char separator) {
        if (chars == null) {
            return new HashMap();
        }
        HashMap params = new HashMap();
        this.chars = chars;
        this.pos = offset;
        this.len = length;

        String paramName = null;
        String paramValue = null;
        while (hasChar()) {// 有待解析的字符
			// 解析出参数名
            paramName = parseToken(new char[] {'=', separator });
            paramValue = null;
            if (hasChar() && (chars[pos] == '=')) {
                pos++; // 跳过"="
                paramValue = parseQuotedToken(new char[] {separator});
            }
            if (hasChar() && (chars[pos] == separator)) {
                pos++; // 跳过分隔符
            }
            if ((paramName != null) && (paramName.length() > 0)) {// 存在参数名
                if (this.lowerCaseNames) {// 参数名小写
                    paramName = paramName.toLowerCase();
                }
                params.put(paramName, paramValue);
            }
        }
        return params;
    }
	
	/**
	 * 直到遇到任何给定的终结符
     * Parses out a token until any of the given terminators
     * is encountered.
     *
     * @param terminators 终止字符数组,遇到任何这些字符时表示结尾
     *
     * @return the token
     */
    private String parseToken(final char[] terminators) {
        char ch;
        i1 = pos;
        i2 = pos;
        while (hasChar()) {
            ch = chars[pos];
            if (isOneOf(ch, terminators)) {// 找到结尾字符
                break;
            }
            i2++;
            pos++;
        }
        return getToken(false);
    }
	
    /**
     * Parses out a token until any of the given terminators
     * is encountered outside the quotation marks.
     * @param terminators 名称/值对的分隔符
     */
    private String parseQuotedToken(final char[] terminators) {
        char ch;
        i1 = pos;
        i2 = pos;
		// 是否去掉引号
        boolean quoted = false;
        boolean charEscaped = false;
        while (hasChar()) {
            ch = chars[pos];
            if (!quoted && isOneOf(ch, terminators)) {
                break;
            }
            if (!charEscaped && ch == '"') {
                quoted = !quoted;
            }
            charEscaped = (!charEscaped && ch == '\\');
            i2++;
            pos++;
        }
        return getToken(true);
    }
	
	/**
     * 此方法会删除前导和尾随空格以及封闭引号
     * @param quoted 是否去除引号
     * @return the token
     */
    private String getToken(boolean quoted) {
        // 除去开始的空格
        while ((i1 < i2) && (Character.isWhitespace(chars[i1]))) {
            i1++;
        }
        // 除去结尾的空格
        while ((i2 > i1) && (Character.isWhitespace(chars[i2 - 1]))) {
            i2--;
        }
        if (quoted) {
            if (((i2 - i1) >= 2) && (chars[i1] == '"')  && (chars[i2 - 1] == '"')) {
                i1++;
                i2--;
            }
        }
        String result = null;
        if (i2 > i1) {
            result = new String(chars, i1, i2 - i1);
        }
        return result;
    }
	
	// true表示字符ch在charray中
    private boolean isOneOf(char ch, final char[] charray) {
        boolean result = false;
        for (int i = 0; i < charray.length; i++) {
            if (ch == charray[i]) {
                result = true;
                break;
            }
        }
        return result;
    }
	
	/**
	 * true-表示有字符需要解析
     */
    private boolean hasChar() {
        return this.pos < this.len;
    }
	
	// 返回参数名是否小写
    public boolean isLowerCaseNames() {
        return this.lowerCaseNames;
    }

    /**
     * 设置参数名是否小写
     */
    public void setLowerCaseNames(boolean b) {
        this.lowerCaseNames = b;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值