代码之家  ›  专栏  ›  技术社区  ›  Zombies

regex是否忽略新行并只匹配整个大字符串?

  •  7
  • Zombies  · 技术社区  · 14 年前

    我这里有一根绳子:

    CREATE UNIQUE INDEX index555 ON
    SOME_TABLE
    (
        SOME_PK          ASC
    );
    

    我想跨多行匹配并匹配SQL语句(所有语句,一个大字符串中会有多个语句)…像这样的,不过我只是在比赛 CREATE UNIQUE INDEX index555 ON

    (CREATE\s.+;)
    

    注意:我想用Java实现这一点。

    5 回复  |  直到 14 年前
        1
  •  17
  •   user405725    14 年前

    编译正则表达式时需要使用dotall和多行标志。这里有一个Java代码示例:

    import java.util.regex.*;
    
    public class test
    {
        public static void main(String[] args)
        {
            String s =
            "CREATE UNIQUE INDEX index555 ON\nSOME_TABLE\n(\n    SOME_PK          ASC\n);\nCREATE UNIQUE INDEX index666 ON\nOTHER_TABLE\n(\n    OTHER_PK          ASC\n);\n";
    
            Pattern p = Pattern.compile("([^;]*?('.*?')?)*?;\\s*", Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.MULTILINE);
    
            Matcher m = p.matcher(s);
    
            while (m.find())
            {
            System.out.println ("--- Statement ---");
            System.out.println (m.group ());
            }
        }
    }
    

    输出将是:

    --- Statement ---
    CREATE UNIQUE INDEX index555 ON
    SOME_TABLE
    (
        SOME_PK          ASC
    );
    
    --- Statement ---
    CREATE UNIQUE INDEX index666 ON
    OTHER_TABLE
    (
        OTHER_PK          ASC
    );
    
        2
  •  8
  •   lowercase    14 年前

    检查 this

    正则表达式。匹配除行终止符以外的任何字符,除非指定了dotall标志

    所以你需要这样做

    Pattern p = Pattern.compile("your pattern", Pattern.DOTALL);
    
        3
  •  5
  •   Alan Moore Chris Ballance    14 年前

    这个 DOTALL 国旗让 . 匹配换行符,但如果只将其应用于现有的regex,则最终将匹配第一个regex中的所有内容。 CREATE 到最后 ; 一箭双雕。如果您想单独匹配这些语句,就需要做更多的工作。一种选择是使用非贪婪量词:

    Pattern p = Pattern.compile("^CREATE\\b.+?;",
        Pattern.DOTALL | Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
    

    我也用过 MULTILINE 旗帜让 ^ 换行后定位匹配,以及 CASE_INSENSITIVE 因为SQL——至少,我听说过的每一种味道。请注意,所有三个标志都具有“inline”表单,您可以在regex本身中使用这些表单:

    Pattern p = Pattern.compile("(?smi)^CREATE\\b.+?;");
    

    (内联形式 道高 s 出于历史原因,它在Perl中被称为“单行”模式,在Perl中,它起源于此。)另一个选项是使用否定的字符类:

    Pattern p = Pattern.compile("(?mi)^CREATE\\b[^;]+;");
    

    [^;]+ 匹配任何字符中的一个或多个,除了 ; --包括换行,所以 S 不需要标记。

    到目前为止,我假定每个语句都从一行的开头开始,以分号结尾,如您的示例中所示。我不认为SQL标准需要这些东西中的任何一个,但是我希望您知道在这个实例中是否可以依赖它们。您可能希望在单词边界而不是线条边界开始匹配:

    Pattern p = Pattern.compile("(?i)\\bCREATE\\b[^;]+;");
    

    最后,如果你想用正则表达式和SQL做更复杂的事情, 不要 . 用regex解析SQL是一个愚蠢的游戏——它比HTML和regex更适合。

        4
  •  3
  •   Kibbee    14 年前

    您将要使用 Pattern.DOTALL 跨行匹配的标志。

        5
  •  3
  •   Don Kirkby    14 年前

    查看可以传递给 Pattern.compile . 我认为多托尔是你需要的。