Skip to content

Instantly share code, notes, and snippets.

@lqt0223
Created February 17, 2017 13:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lqt0223/6c66f6c0f9304e9d0b9acc7cbd505390 to your computer and use it in GitHub Desktop.
Save lqt0223/6c66f6c0f9304e9d0b9acc7cbd505390 to your computer and use it in GitHub Desktop.
01 Write a mapReplace() function in Java(comparing to JavaScript)

用Java写一个mapReplace函数 (与JavaScript的比较)

前言

我个人目前比较熟悉的是JavaScript。因此,这个系列计划通过对比学习的方式,将JavaScript中自己比较熟悉的部分,迁移到Java中实现,并顺带记录和学习Java中的实现方式。

需求

写一个函数,函数名为mapReplace,函数的参数1是一个字符串,其中包含不定数量的数字,参数2是一个函数。该函数的功能是:将参数1的字符串中的数字全部用参数2作同一个算术处理,并将结果替换到字符串原来的位置上

例如,参数1为字符串*"rgb(1,2,3)",参数2为函数f(x)=x+1*,则结果应为*"rgb(2,3,4)"*。

当参数2改为f(x)=x/2时,结果为*"rgb(0.5,1,1.5)"*。

JavaScript中的实现

function mapReplace(string,f){
  //思路,例如输入为"a1b2c3d4"时,将字符串分割为["a1","b2","c3","d4"],对每个部分分别使用replace,替换其中的数字为新值,最后用join方法连接成结果。
  var regexp = /(\d|-|.)+/g;
  var baseIndex = 0;
  var parts = [];
  //JS中的RegExp.exec(string)方法,是比match(),search()功能更强大的正则表达式方法。
  //该函数每次执行会返回一个匹配结果对象,对象中包含了结果本身,结果所在的位置,以及其他信息。
  //有点类似于PHP中的取SQL结果用的 fetch_row()。
  while(result = regexp.exec(string)){
    //取结果
    var number = result[0];
    //取结果在字符串中的位置
    var index = result.index;
    //取结果的长度
    var length = number.length;
    number = parseFloat(number);
    //找到包含一个匹配结果的字符串片段
    var sliced = string.slice(baseIndex, index + length);
    //替换此片段中的数字为新值
    var after = sliced.replace(result[0], f(number));
    parts.push(after);
    baseIndex = index + length; 
  }
    //字符串中余下的片段
  parts.push(string.slice(baseIndex));
  //join所有片段,得到最终结果   
  return parts.join("");
}

Java中的实现的要点

回调

由于我在JavaScript中,把mapReplace()函数设计成第二个参数需要传入一个函数的形式。而Java中没有函数指针,不能把函数名作为参数传入。所以需要使用其他代替的方法来实现。

在JavaScript中,写一个以函数为参数的函数很常见,并且被广泛运用在JavaScript的异步编程、函数式编程中。例如JavaScript中的ajax、Array对象的map, reduce, filter等方法、setTimeout, setInterval的回调方法都是其具体使用。

JavaScript中一个最简单的带回调的函数的定义和其使用:

//定义
function doSomething(data, callback){
  var newData = data + 1;
  callback(data);
}

//使用
doSomething(1,function(newData){
  console.log(newData); //结果为2
});

在Java中,现在广泛使用的回调的实现方式是定义一个接口,在回调函数中重写其方法。如下:

//定义接口
interface Callback{
  public void onCall(int data);
}

public class Callback{
  public static void main(String args[]){
    //"new"一个接口,其实是创建了一个匿名的接口实现类 
    doSomething(1, new Callback(){
      @Override
      //重写这个接口中的方法,决定要怎么使用回调过来的数据
      public void onCall(int newData){
        System.out.println(newData); //结果为2
      }
    });
  }
  //定义一个带有回调的函数
  public static void doSomething(int data, Callback c){
    int newData = data + 1000;
    c.onCall(newData);
  }
}

正则表达式

JavaScript中正则表达式相关的方法集中在RegExp类对象中,还有一部分散见于String类对象中。最常用的 有:

  • 创建一个RegExp对象,使用var re = new RegExp("\\w+")或者var re = /\w+/ 均可。
  • RegExp.exec(String),上面的代码中也有提到,执行一次会返回一个匹配有关的对象,包括匹配所在的位置,匹配的结果,以及其他结果等。如果需要找到所有匹配,需要在循环中使用这一方法。
  • String.match(RegExp),返回一个数组,包含所有匹配结果的子字符串。
  • String.search(RegExp),返回值为Number类型,代表匹配结果所在的位置。找不到则返回-1。
  • String.replace(RegExp,String),返回值为一个新的String,其中所有和RegExp相匹配的部分都会被替换成新的String。

Java中正则表达式相关的方法集中在regex.Pattern, regex.Matcher中,还有一部分在String类对象中。前者在使用时需要import:

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

常用方法有:(根据参数不同,有的方法的作用会有不同。这里只列出最常用的用法,具体还需要多看Oracle文档)

  • 静态方法Pattern.compile(String expression),用以创建一个Pattern对象。该方法将一个正则表达式的字面量的字符串编译,并返回一个Pattern对象。
  • 实例方法pattern.matcher(String string),返回Pattern的Matcher对象来进行匹配操作。第一个参数确定了需要匹配的字符串。
  • 实例方法matcher.find(),返回值为布尔类型,用以确定字符串是否还有下一个匹配。
  • 实例方法matcher.group(),返回值为String类型,即匹配的子字符串。
  • 实例方法matcher.start(),返回值为int类型,即匹配所在的位置。
  • 实例方法matcher.replaceAll(String replacement)matcher.replaceFirst(String replacement),返回值为String,即原字符串中第一个匹配或所有匹配被替换成replacement后的新字符串。
  • 实例方法string.matches(String regex),返回值为布尔类型,说明字符串是否匹配某一正则表达式。
  • 实例方法string.replaceAll(String regex, String replacement)string.replaceFirst(String regex, String replacement),用法与上面的matcher的方法类型。

Java中的实现

import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.ArrayList;

interface Handler{
	 Double handle(Double d);
}

public class Test{
	public static void mapReplace(String s , Handler h){
		String exp = "(\\d|\\.|\\-)+";
		Pattern p = Pattern.compile(exp);
		Matcher m = p.matcher(s);
		int baseIndex = 0;
		ArrayList<String> parts = new ArrayList<String>();
		while(m.find()){
			String numberString = m.group();
			int index = m.start();
			int length = numberString.length();

			Double numberParsed = Double.parseDouble(numberString);
			String sliced = s.substring(baseIndex, index + length);
			String replacement = h.handle(numberParsed).toString();
			String replaced = sliced.replaceFirst(numberString, replacement);
			parts.add(replaced);
			baseIndex = index + length;
		}
		parts.add(s.substring(baseIndex));
		String result = String.join("", parts);
		System.out.println(result);
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment