Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java相当于PHP';s preg_replace_回调_Java_Php_Regex_Preg Replace - Fatal编程技术网

Java相当于PHP';s preg_replace_回调

Java相当于PHP';s preg_replace_回调,java,php,regex,preg-replace,Java,Php,Regex,Preg Replace,我正在将应用程序从PHP迁移到Java,代码中大量使用正则表达式。我在PHP中遇到了一些似乎没有java等价物的东西: preg_replace_callback() 对于正则表达式中的每个匹配项,它调用一个函数,该函数将匹配文本作为参数传递。作为示例用法: $articleText = preg_replace_callback("/\[thumb(\d+)\]/",'thumbReplace', $articleText); # ... function thumbReplace($mat

我正在将应用程序从PHP迁移到Java,代码中大量使用正则表达式。我在PHP中遇到了一些似乎没有java等价物的东西:

preg_replace_callback()
对于正则表达式中的每个匹配项,它调用一个函数,该函数将匹配文本作为参数传递。作为示例用法:

$articleText = preg_replace_callback("/\[thumb(\d+)\]/",'thumbReplace', $articleText);
# ...
function thumbReplace($matches) {
   global $photos;
   return "<img src=\"thumbs/" . $photos[$matches[1]] . "\">";
}
$articleText=preg\u replace\u回调(“/\[thumb(\d+)\]/”,'thumbplace',$articleText);
# ...
函数thumbplace($matches){
全球$照片;
返回“”;
}

在Java中实现这一点的理想方法是什么?

重要的:正如在注释中指出的,如果匹配的正则表达式与替换字符串匹配,则该类有一个无限循环错误。如果必要的话,我将把它作为练习留给读者来解决


我不知道Java内置了什么类似的东西。您可以使用Matcher类轻松推出自己的产品:

import java.util.regex.*;

public class CallbackMatcher
{
    public static interface Callback
    {
        public String foundMatch(MatchResult matchResult);
    }

    private final Pattern pattern;

    public CallbackMatcher(String regex)
    {
        this.pattern = Pattern.compile(regex);
    }

    public String replaceMatches(String string, Callback callback)
    {
        final Matcher matcher = this.pattern.matcher(string);
        while(matcher.find())
        {
            final MatchResult matchResult = matcher.toMatchResult();
            final String replacement = callback.foundMatch(matchResult);
            string = string.substring(0, matchResult.start()) +
                     replacement + string.substring(matchResult.end());
            matcher.reset(string);
        }
    }
}
然后打电话:

final CallbackMatcher.Callback callback = new CallbackMatcher.Callback() {
    public String foundMatch(MatchResult matchResult)
    {
        return "<img src=\"thumbs/" + matchResults.group(1) + "\"/>";
    }
};

final CallbackMatcher callbackMatcher = new CallbackMatcher("/\[thumb(\d+)\]/");
callbackMatcher.replaceMatches(articleText, callback);

对于这个特定的用例,最好只是将回调中的每个匹配项排队,然后向后运行。这将避免在修改字符串时必须重新映射索引。

以下是我对您的建议所做操作的最终结果。我想如果有人也有同样的问题的话,在这里呆着会很好。生成的调用代码如下所示:

content = ReplaceCallback.find(content, regex, new ReplaceCallback.Callback() {
    public String matches(MatchResult match) {
        // Do something special not normally allowed in regex's...
        return "newstring"
    }
});
整个类列表如下所示:

import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.Stack;

/**
 * <p>
 * Class that provides a method for doing regular expression string replacement by passing the matched string to
 * a function that operates on the string.  The result of the operation is then used to replace the original match.
 * </p>
 * <p>Example:</p>
 * <pre>
 * ReplaceCallback.find("string to search on", "/regular(expression/", new ReplaceCallback.Callback() {
 *      public String matches(MatchResult match) {
 *          // query db or whatever...
 *          return match.group().replaceAll("2nd level replacement", "blah blah");
 *      }
 * });
 * </pre>
 * <p>
 * This, in effect, allows for a second level of string regex processing.
 * </p>
 *
 */
public class ReplaceCallback {
    public static interface Callback {
        public String matches(MatchResult match);
    }

    private final Pattern pattern;
    private Callback callback;

    private class Result {
        int start;
        int end;
        String replace;
    }

    /**
     * You probably don't need this.  {@see find(String, String, Callback)}
     * @param regex     The string regex to use
     * @param callback  An instance of Callback to execute on matches
     */
    public ReplaceCallback(String regex, final Callback callback) {
        this.pattern = Pattern.compile(regex);
        this.callback = callback;
    }

    public String execute(String string) {
        final Matcher matcher = this.pattern.matcher(string);
        Stack<Result> results = new Stack<Result>();
        while(matcher.find()) {
            final MatchResult matchResult = matcher.toMatchResult();
            Result r = new Result();
            r.replace = callback.matches(matchResult);
            if(r.replace == null)
                continue;
            r.start = matchResult.start();
            r.end = matchResult.end();
            results.push(r);
        }
        // Improve this with a stringbuilder...
        while(!results.empty()) {
            Result r = results.pop();
            string = string.substring(0, r.start) + r.replace + string.substring(r.end);
        }
        return string;
    }

    /**
     * If you wish to reuse the regex multiple times with different callbacks or search strings, you can create a
     * ReplaceCallback directly and use this method to perform the search and replace.
     *
     * @param string    The string we are searching through
     * @param callback  A callback instance that will be applied to the regex match results.
     * @return  The modified search string.
     */
    public String execute(String string, final Callback callback) {
        this.callback = callback;
        return execute(string);
    }

    /**
     * Use this static method to perform your regex search.
     * @param search    The string we are searching through
     * @param regex     The regex to apply to the string
     * @param callback  A callback instance that will be applied to the regex match results.
     * @return  The modified search string.
     */
    public static String find(String search, String regex, Callback callback) {
        ReplaceCallback rc = new ReplaceCallback(regex, callback);
        return rc.execute(search);
    }
}
import java.util.regex.MatchResult;
导入java.util.regex.Pattern;
导入java.util.regex.Matcher;
导入java.util.Stack;
/**
*
*类,该类通过将匹配的字符串传递给
*对字符串进行操作的函数。然后使用操作的结果替换原始匹配。
*

*示例:

* *查找(“要搜索的字符串”,“/regular(expression/”,new ReplaceCallback.Callback(){ *公共字符串匹配(匹配结果匹配){ *//查询数据库或其他什么。。。 *返回match.group().replaceAll(“第二级替换”,“诸如此类”); * } * }); * * *实际上,这允许进行第二级的字符串正则表达式处理。 *

* */ 公共类替换回调{ 公共静态接口回调{ 公共字符串匹配(匹配结果匹配); } 私人最终模式; 私有回调; 私有类结果{ int启动; 内端; 字符串替换; } /** *您可能不需要它。{@see find(String,String,Callback)} *@param regex要使用的字符串regex *@param callback在匹配项上执行的回调实例 */ 公共替换回调(字符串正则表达式,最终回调){ this.pattern=pattern.compile(regex); this.callback=回调; } 公共字符串执行(字符串){ final Matcher Matcher=this.pattern.Matcher(字符串); 堆栈结果=新堆栈(); while(matcher.find()){ final MatchResult MatchResult=matcher.toMatchResult(); 结果r=新结果(); r、 replace=callback.matches(匹配结果); 如果(r.replace==null) 继续; r、 start=matchResult.start(); r、 end=matchResult.end(); 结果:push(r); } //使用stringbuilder改进此功能。。。 而(!results.empty()){ Result r=results.pop(); string=string.substring(0,r.start)+r.replace+string.substring(r.end); } 返回字符串; } /** *如果希望使用不同的回调或搜索字符串多次重用正则表达式,可以创建 *ReplaceCallback,并使用此方法执行搜索和替换。 * *@param string我们正在搜索的字符串 *@param callback将应用于正则表达式匹配结果的回调实例。 *@返回修改后的搜索字符串。 */ 公共字符串执行(字符串字符串,最终回调){ this.callback=回调; 返回执行(字符串); } /** *使用此静态方法执行正则表达式搜索。 *@param搜索我们正在搜索的字符串 *@param regex要应用于字符串的正则表达式 *@param callback将应用于正则表达式匹配结果的回调实例。 *@返回修改后的搜索字符串。 */ 公共静态字符串查找(字符串搜索、字符串正则表达式、回调){ ReplaceCallback rc=新的ReplaceCallback(regex,callback); 返回rc.execute(search); } }
当您可以在循环中使用appendReplacement()和appendTail()时,尝试模拟PHP的回调功能似乎需要做大量的工作:

public String replaceMatches(String string, Callback callback) {
    String result = "";
    final Matcher matcher = this.pattern.matcher(string);
    int lastMatch = 0;
    while(matcher.find())
    {
        final MatchResult matchResult = matcher.toMatchResult();
        final String replacement = callback.foundMatch(matchResult);
        result += string.substring(lastMatch, matchResult.start()) +
            replacement;
        lastMatch = matchResult.end();
    }
    if (lastMatch < string.length())
        result += string.substring(lastMatch);
    return result;
}

我发现,如果返回的字符串可以再次匹配,jdmichal的答案将是无限循环;下面是一个修改,它阻止无限循环进行这种匹配

final Map<String,String> props = new HashMap<String,String>();
props.put("MY_NAME", "Kip");
props.put("DEPT", "R&D");
props.put("BOSS", "Dave");

String subjectString = "Hi my name is ${MY_NAME} and I work in ${DEPT} for ${BOSS}";
String sRegex = "\\$\\{([A-Za-z0-9_]+)\\}";

String replacement = ReplaceCallback.replace(sRegex, subjectString, new ReplaceCallback.Callback() {
  public String matchFound(MatchResult match) {
    String group1 = match.group(1);
    if(group1 != null && props.containsKey(group1))
      return props.get(group1);
    return match.group();
  }
});

System.out.println("replacement: " + replacement);
公共字符串替换匹配(字符串、回调){
字符串结果=”;
final Matcher Matcher=this.pattern.Matcher(字符串);
int lastMatch=0;
while(matcher.find())
{
final MatchResult MatchResult=matcher.toMatchResult();
最终字符串替换=callback.foundMatch(matchResult);
结果+=字符串.substring(lastMatch,matchResult.start())+
替换
lastMatch=matchResult.end();
}
if(lastMatch
我对这里的任何解决方案都不太满意。我想要一个无状态的解决方案。如果我的替换字符串恰好与模式匹配,我也不想以无限循环结束。在这期间,我添加了对
limit
参数和返回的
count
参数的支持。(我使用了
AtomicIn。)
public String replaceMatches(String string, Callback callback) {
    String result = "";
    final Matcher matcher = this.pattern.matcher(string);
    int lastMatch = 0;
    while(matcher.find())
    {
        final MatchResult matchResult = matcher.toMatchResult();
        final String replacement = callback.foundMatch(matchResult);
        result += string.substring(lastMatch, matchResult.start()) +
            replacement;
        lastMatch = matchResult.end();
    }
    if (lastMatch < string.length())
        result += string.substring(lastMatch);
    return result;
}
final Map<String,String> props = new HashMap<String,String>();
props.put("MY_NAME", "Kip");
props.put("DEPT", "R&D");
props.put("BOSS", "Dave");

String subjectString = "Hi my name is ${MY_NAME} and I work in ${DEPT} for ${BOSS}";
String sRegex = "\\$\\{([A-Za-z0-9_]+)\\}";

String replacement = ReplaceCallback.replace(sRegex, subjectString, new ReplaceCallback.Callback() {
  public String matchFound(MatchResult match) {
    String group1 = match.group(1);
    if(group1 != null && props.containsKey(group1))
      return props.get(group1);
    return match.group();
  }
});

System.out.println("replacement: " + replacement);
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.*;

public class ReplaceCallback
{
  public static interface Callback {
    /**
     * This function is called when a match is made. The string which was matched
     * can be obtained via match.group(), and the individual groupings via
     * match.group(n).
     */
    public String matchFound(MatchResult match);
  }

  /**
   * Replaces with callback, with no limit to the number of replacements.
   * Probably what you want most of the time.
   */
  public static String replace(String pattern, String subject, Callback callback)
  {
    return replace(pattern, subject, -1, null, callback);
  }

  public static String replace(String pattern, String subject, int limit, Callback callback)
  {
    return replace(pattern, subject, limit, null, callback);
  }

  /**
   * @param regex    The regular expression pattern to search on.
   * @param subject  The string to be replaced.
   * @param limit    The maximum number of replacements to make. A negative value
   *                 indicates replace all.
   * @param count    If this is not null, it will be set to the number of
   *                 replacements made.
   * @param callback Callback function
   */
  public static String replace(String regex, String subject, int limit,
          AtomicInteger count, Callback callback)
  {
    StringBuffer sb = new StringBuffer();
    Matcher matcher = Pattern.compile(regex).matcher(subject);
    int i;
    for(i = 0; (limit < 0 || i < limit) && matcher.find(); i++)
    {
      String replacement = callback.matchFound(matcher.toMatchResult());
      replacement = Matcher.quoteReplacement(replacement); //probably what you want...
      matcher.appendReplacement(sb, replacement);
    }
    matcher.appendTail(sb);

    if(count != null)
      count.set(i);
    return sb.toString();
  }
}
replace(Pattern.compile("cat"), mr -> "dog", "one cat two cats in the yard")
Pattern.compile("random number")
    .matcher("this is a random number")
    .replaceAll(r -> "" + ThreadLocalRandom.current().nextInt()) 
this is a -107541873
Patern.compile("regex").matcher("some string")
     .replaceAll(matchResult -> "something" + matchResult.group());