【问题标题】:Java : Finding String literals in StringJava:在字符串中查找字符串文字
【发布时间】:2017-05-18 06:26:18
【问题描述】:

假设我有一个字符串:

look_up_check('US_POPULATION','('POPULATION' = 3844829) and ('CITY' = 'Los Angeles')')

现在,我必须找到:'US_POPULATION' , 'POPULATION', 'CITY' , 'Los Angeles'

我尝试过使用基于堆栈的方法,但没有达到标准。我可以使用 regex 或任何其他方法吗?

【问题讨论】:

  • 输入字符串中的' 不平衡(有奇数个)。所以第二个字符串实际上是'('
  • 哦...让我编辑一下。

标签: java regex string stack


【解决方案1】:

我将提供一个无正则表达式的解决方案。

字符串引号内的内容当前是:

US_POPULATION
(
 = 3844829) and (
 = 
)

这不是你想要的。要得到你想要的字符串,引号必须这样排列:

look_up_check('US_POPULATION',('POPULATION' = 3844829) and ('CITY' = 'Los Angeles'))

解决方案:

public static List<String> findStuffInQuotes(String s) {
    List<String> list = new ArrayList<>();
    StringBuilder sb = new StringBuilder();
    boolean insideQuotes = false;
    for (int i = 0 ; i < s.length() ; i++) {
        if (s.charAt(i) == '\'') {
            insideQuotes = !insideQuotes;
            if (!insideQuotes) {
                list.add(sb.toString());
                sb = new StringBuilder();
            }
        } else if (insideQuotes) {
            sb.append(s.charAt(i));
        }
    }
    list.add(sb.toString());
    return list;
}

【讨论】:

  • 没关系。没问题。
【解决方案2】:

例如,您可以使用正则表达式:

String str = "look_up_check('US_POPULATION','('POPULATION' = 3844829) and ('CITY' = 'Los Angeles')')";
Pattern p = Pattern.compile("'[\\w\\s]+'");
Matcher m = p.matcher(str);

while (m.find()) {
    System.out.println(m.group());
}

输出

'US_POPULATION'
'POPULATION'
'CITY'
'Los Angeles'

Regex demo

【讨论】:

  • 这对字符串文字的内容做出了一些沉重的假设。
  • 我最终是这样实现的:regex101.com/r/atL7z4/1 有什么建议吗?
  • 你能给我举个例子吗@Henry 你是什么意思?
  • @YCF_L 例如,它不适用于此'Washington, D.C.'。是否存在问题取决于上下文。
  • 正则表达式按预期工作 - 它收集由单引号字符分隔的字符串文字。但是@Bond 提供的引用字符串格式不符合要求,因为它将字符串嵌入到其他字符串中而没有转义分隔符。
【解决方案3】:

要拥有比正则表达式和手写词法分析器更强大的东西,您可以使用类似 Flex 的工具来创建一个。我在 JFlex+CUP(http://jflex.de/manual.htmlhttp://www2.cs.tum.edu/projects/cup/install.php)中创建了一个简单的解析器,用于解析您提供的文本。

首先,您需要创建 .flex 文件来描述生成令牌的规则:

import java_cup.runtime.*;
import java.util.*;

%%
%unicode
%class LexicalAnalyzer
%line
%column
%cup

/*numbers*/
number      = ([1-9][0-9]*| 0)([.][0-9]+ )?([eE]([+]|[-])?[0-9]+)?
digit       = [0-9]
underscore = [_]


identifier = {identifier5} ( [.] {identifier5} )*

identifier2 = {letter} ({letter}|{digit}|{underscore})*
identifier3 = {digit} ({letter}|{digit}|{underscore})+
identifier4 = {underscore} ({letter}|{digit}|{underscore})+
identifier5     = {identifier2} | {identifier3} | {identifier4}
letter      = {lowercase} | {uppercase}
lowercase   = [a-z]
uppercase   = [A-Z]
inputchar   = [^\r\n]

/*Comments*/
lineterminator  = \r | \n | \r\n
simplecomment   = "//" {inputchar}* {lineterminator}
blockcomment    = "/*" ( [^*]* | "*"+ [^/*] )* "*"+ "/" 


%{

private void error(){
    System.err.print("Sintax error on line " + (yyline+1));
    System.err.println(". Unrecognizable token: \"" + yytext() + "\"");
    //System.exit(1);
}

private Symbol processToken(int type, Object value) {
    System.out.println("Type: " + type);
        System.out.println("Value: " + value );
        return new Symbol(type);
}

StringBuffer str = new StringBuffer();

%}

%state STRING
%state END

%%

<YYINITIAL> {
    /* string literals */

    [']        {str.setLength(0);yybegin(STRING);}

        "and" { return processToken( sym.AND , yytext()); }



    /* number literals */
    {number} { return processToken(sym.NUMBER , yytext()); }

    /* identifiers */


    {identifier} { return processToken( sym.IDENTIFIER , yytext()); }


    "("    { return processToken( sym.OPENP , yytext()); }
    ")"    { return processToken( sym.CLOSEP , yytext()); }
    "="  { return processToken(sym.EQUALS , yytext());  }
    ","  { return processToken(sym.COMMA , yytext());  }
    "+"  { return processToken(sym.OP , yytext());  }
    "-"  { return processToken(sym.OP , yytext());  }
    "*"  { return processToken(sym.OP , yytext());  }
    "/"  { return processToken(sym.OP , yytext());    }


    // whitespace and comments
    {simplecomment} {/* Do nothing */}
    {blockcomment}  {} 
    " "|\t|\n|  {lineterminator}    {/* Do nothing */}
        .               {error();}
    //.             { /*error!*/ } 
}



/* literais string */
<STRING> {
    [']              { yybegin(YYINITIAL); return processToken( sym.STRING , str.toString()); } 
    \\t             { str.append('\t'); }
    \\n             { str.append('\n'); }
    \\r             { str.append('\r'); }
    \\\"            { str.append('\"'); }
    \\\\            { str.append('\\'); }
    \\[']           { str.append('\''); }
    \\[0-9][0-9][0-9] 
    {
        String s = yytext().substring(1);
        s = "" + ((char) Integer.parseInt(s));
        str.append( s );
    }
    [^\n\r\'\\\t]+    { str.append( yytext() ); }
    .               { /* malformed string */}
}

<END>{
    \n  {}
    .   {}
}

然后,您需要使用 JFlex.jar 编译此解析器规范

java -jar JFlex.jar lexical.flex

它将创建一个名为“LexicalAnalyzer.java”的源文件,您可以使用它根据您的规范将字符串分解为标记。

public class Parser {


    public static void main(String[] args) throws Exception {

    String str = "look_up_check('US POPULATION', ( 'POPULATION' = 3844829 ) and ('CITY' = 'Los Angeles'))";

    ByteArrayInputStream buff = new ByteArrayInputStream(str.getBytes());

    LexicalAnalyzer l = new LexicalAnalyzer(buff);

    Symbol s = l.next_token();

    while(s.sym != sym.EOF){
        s = l.next_token();
    }

    }

}

产生输出:

Type: 5
Value: look_up_check
Type: 3
Value: (
Type: 1
Value: US POPULATION
Type: 9
Value: ,
Type: 3
Value: (
Type: 1
Value: POPULATION
Type: 8
Value: =
Type: 7
Value: 3844829
Type: 4
Value: )
Type: 2
Value: and
Type: 3
Value: (
Type: 1
Value: CITY
Type: 8
Value: =
Type: 1
Value: Los Angeles
Type: 4
Value: )
Type: 4
Value: )

编辑: sym.java 类

public class sym {
    public static int STRING = 1;
    public static int AND = 2;
    public static int OPENP = 3;
    public static int CLOSEP = 4;
    public static int IDENTIFIER = 5;
    public static int OP = 6;
    public static int NUMBER = 7;
    public static int EQUALS = 8;
    public static int COMMA = 9;
    public static int EOF = 10;
}

【讨论】:

  • 是不是有点过度设计了?
  • @Henry 这比看起来容易,知道如何编写这样的解析器对程序员工具箱来说是一个很好的资产。根据您要解析的事物的复杂性,它是比使用正则表达式更好的方法。
  • "根据您要解析的事物的复杂性,它是比使用正则表达式更好的方法。"这是这里的关键句。我同意,正则表达式不是正确的解析工具(除了词法标记的识别)。但是您的解决方案对于手头的任务来说太复杂了。例如,为什么我们需要识别 cmets?
  • 啊,谢谢你的澄清。我调整了我正在使用的解析器,但我忘了删除这些规则。它们可以毫无问题地被移除。您可以使用此示例作为模板,根据需要删除或添加更多规则。它可以正确识别数字、标识符、保留字(在本例中为“and”)和一些运算符。
猜你喜欢
  • 2014-02-04
  • 2011-01-11
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
  • 2011-07-13
  • 2014-03-26
  • 2016-01-26
相关资源
最近更新 更多