首页 > 解决方案 > Java 正则表达式与 PHP,悬空元字符“?”

问题描述

即使这是一个 Java 问题,我也用 PHP 来标记它。正则表达式是从 PHP 源复制的,所以我希望一些 PHPers 可以帮助解决这个问题。

我决定构建一个简单的垃圾邮件过滤器,只是为了好玩,我从 MediaWiki 复制了垃圾邮件阻止列表:https ://meta.wikimedia.org/wiki/Spam_blacklist

大多数情况下,这似乎有效,但一些模式因语法错误而失败。我不知道这是一个错字还是 PHP 使用的语法与 Java 不同。谁能帮我修复这些正则表达式以便它们编译?

以下是问题:

java.util.regex.PatternSyntaxException: Dangling meta character '?' near index 17
\bfacebo(?:o[ob]|?o)k\.com\b
                 ^
java.util.regex.PatternSyntaxException: Dangling meta character '?' near index 5
\b????\.tk\b
     ^
java.util.regex.PatternSyntaxException: Dangling meta character '?' near index 0
??\.xsl\.pt\b
^
java.util.regex.PatternSyntaxException: Dangling meta character '?' near index 4
\b????\.shop\b
    ^
java.util.regex.PatternSyntaxException: Dangling meta character '?' near index 4
\b???\.??\b
    ^

如果您有兴趣,这是编译它们的代码。我不认为这有什么不同。

   private static synchronized void init() throws IOException {
      
      if( blackListPatterns.get() != null ) return;
      InputStream blacklistfile = SpamBlackList.class.getResourceAsStream( "blacklist.txt" );
      BufferedReader buf = new BufferedReader( new InputStreamReader( blacklistfile, "UTF-8" ) );
      ArrayList<String> blacklist = new ArrayList<>( 12000 );
      for( String line; (line = buf.readLine()) != null; )
         if( !line.isBlank() && line.trim().charAt(0) != '#' )
            blacklist.add( line );
      ArrayList<Pattern> tempPatterns = new ArrayList<>( blacklist.size() );
      for( String pat : blacklist )
         try {
            tempPatterns.add( Pattern.compile( pat ) );
         } catch ( java.util.regex.PatternSyntaxException ex ) {
            System.err.println( ex );  // should log this, low level like FINER
         }
      blackListPatterns = new WeakReference<>( tempPatterns );
   }
   
   private static volatile WeakReference<List<Pattern>> 
           blackListPatterns = new WeakReference( null );

标签: javaphpregex

解决方案


您下载的https://meta.wikimedia.org/wiki/Spam_blacklist ( )副本blacklist.txt已损坏。悬空的问号是非 ASCII 字符,例如\bfacebo(?:o[ob]|?o)k\.com\bis 实际上\bfacebo(?:o[ob]|ıo)k\.com\b。请注意无点的“ı”。

下载https://meta.wikimedia.org/wiki/Spam_blacklist?action=raw并考虑到它是 UTF-8。

您可能希望将 Unicode 标志传递给正则表达式。还要考虑到:

这里所说的正则表达式不是正确的正则表达式,而是插入到硬编码的正则表达式中的子模式。即上面的子模式Foo 将创建一个像/^Foo$/usi 这样的正则表达式。

(见https://www.mediawiki.org/wiki/Extension:TitleBlacklist#Block_list)。


推荐阅读