【问题标题】:Java String parsing - {k1=v1,k2=v2,...}Java 字符串解析 - {k1=v1,k2=v2,...}
【发布时间】:2010-12-11 07:27:34
【问题描述】:

我有以下可能包含约 100 个条目的字符串:

String foo = "{k1=v1,k2=v2,...}"

并希望编写以下函数:

String getValue(String key){
    // return the value associated with this key
}

我想在不使用任何解析库的情况下执行此操作。有什么快速的想法吗?

【问题讨论】:

  • 我的解析库你是说正则表达式,还是没有第三方库?
  • v1、v2...可以包含'='或','吗?
  • 假设值不包含“=”或“,”。只是没有第三方库。
  • 这真的非常接近 JSON。为什么不使用它?
  • (另外:Java 中没有第 3 方库?疯狂。)

标签: java text-parsing


【解决方案1】:

如果您知道您的字符串将始终如下所示,请尝试以下操作:

HashMap map = new HashMap();

public void parse(String foo) {
  String foo2 = foo.substring(1, foo.length() - 1);  // hack off braces
  StringTokenizer st = new StringTokenizer(foo2, ",");
  while (st.hasMoreTokens()) {
    String thisToken = st.nextToken();
    StringTokenizer st2 = new StringTokenizer(thisToken, "=");

    map.put(st2.nextToken(), st2.nextToken());
  }
}

String getValue(String key) {
  return map.get(key).toString();
}

警告:我实际上并没有尝试过;可能有轻微的语法错误,但逻辑应该是合理的。请注意,我还进行了完全零错误检查,因此您可能希望使我所做的更加稳健。

【讨论】:

  • 快捷方式是使用",={}" 。不需要破解大括号或第二个标记器:)
【解决方案2】:

我能想到的最快但最丑陋的答案是使用状态机逐个字符地解析它。它非常快,但非常具体且非常复杂。在我看来,你可以有几种状态:

  • 解析密钥
  • 解析值
  • 准备就绪

例子:

int length = foo.length();
int state = READY;
for (int i=0; i<length; ++i) {
   switch (state) {
      case READY:
        //Skip commas and brackets
        //Transition to the KEY state if you find a letter
        break;
      case KEY:
        //Read until you hit a = then transition to the value state
        //append each letter to a StringBuilder and track the name
        //Store the name when you transition to the value state
        break;
      case VALUE:
        //Read until you hit a , then transition to the ready state
        //Remember to save the built-key and built-value somewhere
        break;
   }
}

此外,您可以使用 StringTokenizers(速度快)或 Regexs(速度较慢)更快地实现这一点。但总的来说,单个字符解析很可能是最快的方法。

【讨论】:

  • 对于原始速度,使用 char 数组来避免同步。嗯,这是一个老式的反射,因为现代 JVM 粗化了锁 :-)
  • 哦,好电话。我实际上完全忘记了如何实际访问角色......
【解决方案3】:

未经测试编写:

String result = null;
int i = foo.indexOf(key+"=");
if (i != -1 && (foo.charAt(i-1) == '{' || foo.charAt(i-1) == ',')) {
    int j = foo.indexOf(',', i);
    if (j == -1) j = foo.length() - 1;
    result = foo.substring(i+key.length()+1, j);
}
return result;

是的,它很丑:-)

【讨论】:

    【解决方案4】:

    好吧,假设值中没有 '=' 或 ',',最简单(且简陋)的方法是:

    int start = foo.indexOf(key+'=') + key.length() + 1;
    int end =  foo.indexOf(',',i) - 1;
    if (end==-1) end = foo.indexOf('}',i) - 1;
    return (start<end)?foo.substring(start,end):null;
    

    是的,不推荐:)

    【讨论】:

    • 别以为我会用这个,但有趣的答案!
    • 哦,我知道这不是好方法:) 我只是想表明这是一种快速的方法。但是有些用户比我快,并且之前发布了类似的解决方案。我在其他答案中也没有看到好的解决方案,最终的解决方案将暗示使用 AST 解析器或类似的东西。
    【解决方案5】:

    如果字符串有很多条目,您最好在不使用 StringTokenizer 的情况下手动解析以节省一些内存(如果您必须解析数千个这样的字符串,那么额外的代码是值得的):

    
    public static Map parse(String s) {
        HashMap map = new HashMap();
        s = s.substring(1, s.length() - 1).trim(); //get rid of the brackets
        int kpos = 0; //the starting position of the key
        int eqpos = s.indexOf('='); //the position of the key/value separator
        boolean more = eqpos > 0;
        while (more) {
            int cmpos = s.indexOf(',', eqpos + 1); //position of the entry separator
            String key = s.substring(kpos, eqpos).trim();
            if (cmpos > 0) {
                map.put(key, s.substring(eqpos + 1, cmpos).trim());
                eqpos = s.indexOf('=', cmpos + 1);
                more = eqpos > 0;
                if (more) {
                    kpos = cmpos + 1;
                }
            } else {
                map.put(key, s.substring(eqpos + 1).trim());
                more = false;
            }
        }
        return map;
    }
    

    我用这些字符串测试了这段代码,它工作正常:

    {k1=v1}

    {k1=v1,k2=v2,k3=v3,k4=v4}

    {k1= v1,}

    【讨论】:

      【解决方案6】:

      添加代码以检查foo 中是否存在key 留给读者作为练习:-)

      String foo = "{k1=v1,k2=v2,...}";
      
      String getValue(String key){
          int offset = foo.indexOf(key+'=') + key.length() + 1;
          return foo.substring(foo.indexOf('=', offset)+1,foo.indexOf(',', offset));
      }
      

      【讨论】:

        【解决方案7】:

        请找到我的解决方案:

        public class KeyValueParser {
        
            private final String line;
            private final String divToken;
            private final String eqToken;
            private Map<String, String> map = new HashMap<String, String>();
        
            // user_uid=224620; pass=e10adc3949ba59abbe56e057f20f883e;
            public KeyValueParser(String line, String divToken, String eqToken) {
                this.line = line;
                this.divToken = divToken;
                this.eqToken = eqToken;
                proccess();
            }
        
            public void proccess() {
                if (Strings.isNullOrEmpty(line) || Strings.isNullOrEmpty(divToken) || Strings.isNullOrEmpty(eqToken)) {
                    return;
                }
                for (String div : line.split(divToken)) {
                    if (Strings.isNullOrEmpty(div)) {
                        continue;
                    }
                    String[] split = div.split(eqToken);
                    if (split.length != 2) {
                        continue;
                    }
                    String key = split[0];
                    String value = split[1];
                    if (Strings.isNullOrEmpty(key)) {
                        continue;
                    }
                    map.put(key.trim(), value.trim());
                }
        
            }
        
            public String getValue(String key) {
                return map.get(key);
            }
        }
        

        用法

        KeyValueParser line = new KeyValueParser("user_uid=224620; pass=e10adc3949ba59abbe56e057f20f883e;", ";", "=");
        String userUID = line.getValue("user_uid")
        

        【讨论】:

          猜你喜欢
          • 2012-02-03
          • 2018-10-15
          • 1970-01-01
          • 2015-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-11-26
          • 2011-01-16
          相关资源
          最近更新 更多