【问题标题】:Java regex of string字符串的Java正则表达式
【发布时间】:2013-11-17 02:19:29
【问题描述】:

我想解析字符串以从中获取字段。字符串的格式(来自数据集)是这样的(-> 代表一个制表符,* 代表一个空格):

Date(yyyymmdd)->Date(yyyymmdd)->*City,*State*-->Description

我只对第一次约会和状态感兴趣。我试过这样的正则表达式:

String txt="19951010    19951011     Red City, WI                 Description";

    String re1="(\\d+)";    // Integer Number 1
    String re2=".*?";   // Non-greedy match on filler
    String re3="(?:[a-z][a-z]+)";   // Uninteresting: word
    String re4=".*?";   // Non-greedy match on filler
    String re5="(?:[a-z][a-z]+)";   // Uninteresting: word
    String re6=".*?";   // Non-greedy match on filler
    String re7="((?:[a-z][a-z]+))"; // Word 1

    Pattern p = Pattern.compile(re1+re2+re3+re4+re5+re6+re7,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
    Matcher m = p.matcher(txt);
    if (m.find())
    {
        String int1=m.group(1);
        String word1=m.group(2);
        System.out.print("("+int1.toString()+")"+"("+word1.toString()+")"+"\n");
    }

如果城市有两个词(红色城市),则可以正常提取状态,但如果城市只有一个词,则无法正常工作。我想不通,我不需要使用正则表达式并且愿意接受任何其他建议。谢谢。

【问题讨论】:

    标签: java regex parsing mapreduce


    【解决方案1】:

    问题:

    您的问题是您当前正则表达式的每个组成部分本质上都匹配一个数字或 [a-z] 单词,由任何不是 [a-z] 的内容(包括逗号)分隔。所以你对一个两个词城市的部分是:

    Input: 
      19951010 19951011 Red City, WI Description
    
    Your components:
      String re1="(\\d+)";    // Integer Number 1
      String re2=".*?";   // Non-greedy match on filler
      String re3="(?:[a-z][a-z]+)";   // Uninteresting: word
      String re4=".*?";   // Non-greedy match on filler
      String re5="(?:[a-z][a-z]+)";   // Uninteresting: word
      String re6=".*?";   // Non-greedy match on filler
      String re7="((?:[a-z][a-z]+))"; // Word 1
    
    What they match:
      re1: "19951010"
      re2: " 19951011 "
      re3: "Red" (stops at non-letter, e.g. whitespace)
      re4: " "
      re5: "City" (stops at non-letter, e.g. the comma)
      re6: ", " (stops at word character)
      re7: "WI"
    

    但是用一个单词的城市:

    Input: 
      19951010 19951011 Pittsburgh, PA Description
    
    What they match:
      re1: "19951010"
      re2: " 19951011 "
      re3: "Pittsburgh" (stops at non-letter, e.g. the comma)
      re4: ","
      re5: "PA" (stops at non-letter, e.g. whitespace)
      re6: " " (stops at word character)
      re7: "Description" (but you want this to be the state)
    


    解决方案:

    你应该做两件事。首先,稍微简化一下你的正则表达式;你会有点疯狂地指定贪婪与不情愿等。只需使用贪婪模式。其次,想想表达规则的最简单方式。

    你的规则真的是:

    • 日期
    • 一堆不是逗号的字符(包括第二个日期和城市名称)。
    • 逗号。
    • 状态(一个字)。

    所以构建一个坚持这一点的正则表达式。您可以像现在一样,通过跳过第二个数字来走捷径,但请注意,您确实会失去对以数字开头的城市的支持(这可能不会发生)。你也不关心国家。所以,例如:

    String re1 = "(\\d+)";   // match first number
    String re2 = "[^,]*";    // skip everything thats not a comma
    String re3 = ",";        // skip the comma
    String re4 = "[\\s]*";   // skip whitespace
    String re5 = "([a-z]+)"; // match letters (state)
    
    String regex = re1 + re2 + re3 + re4 + re5;
    

    还有其他选项,但我个人认为正则表达式对于此类事情非常简单。您可以使用split() 的各种组合,正如其他海报所详述的那样。您可以使用indexOf() 直接查找逗号和空格并提取子字符串。您甚至可以说服 Scanner 或 StringTokenizer 或 StreamTokenizer 为您工作。但是,存在正则表达式来解决此类问题,并且是完成这项工作的好工具。

    这是StringTokenizer 的示例:

    StringTokenizer t = new StringTokenizer(txt, " \t");
    String date = t.nextToken();
    t.nextToken(); // skip second date
    t.nextToken(","); // change delimiter to comma and skip city
    t.nextToken(" \t"); // back to whitespace and skip comma
    String state = t.nextToken();
    

    不过,我觉得正则表达式更清晰地表达了规则。

    顺便说一句,为了将来的调试,有时打印出所有捕获组会有所帮助,这可以让您深入了解什么匹配什么。一个好的技术是将正则表达式的每个 组件暂时放在一个捕获组中,然后将它们全部打印出来。

    【讨论】:

      【解决方案2】:

      不需要这么复杂。你可以在空格上分割!

      //s is your string
      String[] first = s.split("\\s*,\\s*")
      String[] firstHalf = first[0].split("\\s+")
      String[] secondHalf = first[1].split("\\s+")
      String date = firstHalf[0]
      String state = secondHalf[0]
      

      现在你有你的date 和你的state!对他们做你想做的事。

      【讨论】:

      • 这与 OP 的正则表达式存在相同的问题,如果城市不是两个词,它将失败。您想要做的是在逗号处拆分字符串,然后在空格处拆分每个字符串,然后在每个字符串中获取第一个标记。
      • 很公平。我只是基于问题中“*”和“->”的位置
      • 现在应该可以正常工作了!感谢您指出这一点,我应该更仔细地阅读这个问题!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多