【正則表達式】使用正則表達式的group,查找出String中的參數值


需求

指標基本格式:

clm.{type}.{hostId}.$metricItem

示例1:

// 待匹配表達式:<hostId: 為36位的UUID>
summarize(clm.pm.xxx.yyy.uuu.zzz.0193f1b3-7bcc-4374-8546-8e87b7276003.agg.cpu.percent-avg.system,'10min','avg',true)

希望匹配出:
- type: pm.xxx.yyy.uuu.zzz
- hostId: 0193f1b3-7bcc-4374-8546-8e87b7276003

返回的Map為:
{hostId=0193f1b3-7bcc-4374-8546-8e87b7276003, type=pm.xxx.yyy.uuu.zzz}

示例2:

// 待匹配表達式:<hostId: 為36位的UUID>  
summarize(clm.pm.0193f1b3-7bcc-4374-8546-8e87b7276003.agg.cpu.percent-avg.system,'10min','avg',true)

希望匹配出:
- type: pm
- hostId: 0193f1b3-7bcc-4374-8546-8e87b7276003

返回的Map為:
{hostId=0193f1b3-7bcc-4374-8546-8e87b7276003, type=pm}

示例3:

// 待匹配表達式:<hostId: 使用 "_"分割的IP地址> 
summarize(clm.pm.xxx.yyy.uuu.zzz.10_144_202_141.agg.cpu.percent-avg.system,'10min','avg',true)

希望匹配出:
- type: pm.xxx.yyy.uuu.zzz
- hostId: 0193f1b3-7bcc-4374-8546-8e87b7276003

返回的Map為:
{hostId=10_144_202_141, type=pm.xxx.yyy.uuu.zzz}

基本思路

使用正則表達式的group()去獲取結果;

  • group()正則表示中,使用小括號()表示不同的group,有多少個開括號(,就會有多少個組,表示為:group(0)、group(1)、group(N);
  • group()正則表示中,可以為不同的group添加名稱,如<type><hostId>,方便匹配;

對於示例1示例2,可使用下面的group()表達式去匹配:

// hostId: 為36位的UUID
"^.*clm\\.(?<type>\\w+\\.*.*)\\.(?<hostId>\\w{8}(?:-\\w{4}){3}-\\w{12}?)"

解析:
上面包括多個組,下面僅介紹感興趣的組,比如:
1. (?<type>\\w+\\.*.*) : 別名為 type,匹配此()內的值;
2. (?<hostId>\\w{8}(?:-\\w{4}){3}-\\w{12}?): 別名為 hostId,匹配此()內的值(注:為最外層的小括號)

對於示例3,可使用下面的group()表達式去匹配:

// hostId: 使用 "_"分割的IP地址
"^.*clm\\.(?<type>\\w+\\.*.*)\\.(?<hostId>\\d{0,3}_\\d{0,3}_\\d{0,3}_\\d{0,3})"

代碼實現

RegexGroupUtils.java

import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

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

public class RegexGroupUtils {
    private static final Pattern groupAlias = Pattern.compile("\\<(.*?)\\>");

    /**
     * 使用正則表達式的group,查找出String中的參數值;<br/>
     * 示例如下:
     * <pre>{@code
     *  // 格式:
     *  clm.{type}.{hostId}.$metricItem
     *
     *  // 待匹配表達式:<hostId: 為36位的UUID>
     *  summarize(clm.pm.xxx.yyy.uuu.zzz.0193f1b3-7bcc-4374-8546-8e87b7276003.agg.cpu.percent-avg.system,'10min','avg',true)
     *
     *  希望匹配出:
     *  - type: pm.xxx.yyy.uuu.zzz
     *  - hostId: 0193f1b3-7bcc-4374-8546-8e87b7276003
     *
     *  返回的Map為:
     *  {hostId=0193f1b3-7bcc-4374-8546-8e87b7276003, type=pm.xxx.yyy.uuu.zzz}
     * }</pre>
     *
     * @param sourceString 待匹配的字符串
     * @param pattern      正則表達式
     * @return
     */
    public static Map<String, String> findParams(String pattern, String sourceString) {
        Map<String, String> mapResult = Maps.newConcurrentMap();

        if (Strings.isNullOrEmpty(sourceString) || ObjectUtils.isEmpty(pattern)) {
            return mapResult;
        }

        // 找出pattern中以"<xxxx>"表示的組別名
        Set<String> groupNames = PlaceHolderReplaceUtils.findPlaceHolderKeys(pattern, groupAlias);
        if (CollectionUtils.isEmpty(groupNames)) {
            return mapResult;
        }

        // 創建 Pattern 對象
        Pattern r = Pattern.compile(pattern);

        // 現在創建 matcher 對象
        Matcher m = r.matcher(sourceString);
        if (m.find()) {
            for (String param : groupNames) {
                String value = m.group(param);
                if (!Strings.isNullOrEmpty(value)) {
                    mapResult.put(param, value);
                }
            }
        }

        return mapResult;
    }

}

PlaceHolderReplaceUtils.java

import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Desc: 占位符替換, 占位符表示為:{@code {placeholder}};
 * <p>
 * 示例:替換如下{xxx}占位符中的內容
 * <pre>"名字:{name},年齡:{age},學校:{school}"</pre>
 */
public class PlaceHolderReplaceUtils {
    private static final Pattern pattern = Pattern.compile("\\{(.*?)\\}");
    private static Matcher matcher;

    /**
     * 查找String中的占位符keys;<br/>
     * 示例: "名字:{name},年齡:{age},學校:{school}", 則返回:Set[name,age,school]
     * <p>
     * pattern示例:
     * <pre> {@code
     *  // 尖括號:<placeHolder> 表示為占位符
     *  Pattern pattern = Pattern.compile("\\<(.*?)\\>");
     *
     *  // 大括號:{placeHolder} 表示為占位符, 上面的示例中就使用{}作為占位符
     *  Pattern pattern = Pattern.compile("\\{(.*?)\\}");
     * }
     * </pre>
     *
     * @param sourceString
     * @param pattern
     * @return
     */
    public static Set<String> findPlaceHolderKeys(String sourceString, Pattern pattern) {
        Set<String> placeHolderSet = Sets.newConcurrentHashSet();

        if (Strings.isNullOrEmpty(sourceString) || ObjectUtils.isEmpty(pattern)) {
            return placeHolderSet;
        }

        String targetString = sourceString;
        matcher = pattern.matcher(sourceString);
        while (matcher.find()) {
            String key = matcher.group();  //示例: {name}
            String placeHolder = key.substring(1, key.length() - 1).trim();  //示例: name
            placeHolderSet.add(placeHolder);
        }

        return placeHolderSet;
    }

}

測試代碼

import org.junit.Test;

public class RegexGroupUtilsTest {
    @Test
    public void findParams() {
        //-----------start 測試匹配 uuid(32-36位)
        String line1 = "summarize(clm.pm.xxx.yyy.uuu.zzz.0193f1b3-7bcc-4374-8546-8e87b7276003.agg.cpu.percent-avg.system,'10min','avg'," +
                "true)";
        String line2 = "summarize(clm.pm.0193f1b3-7bcc-4374-8546-8e87b7276003.agg.cpu.percent-avg.system,'10min','avg',true)";
        String pattern = "^.*clm\\.(?<type>\\w+\\.*.*)\\.(?<hostId>\\w{8}(?:-\\w{4}){3}-\\w{12}?)"; //OK

        System.out.println("-----line1--------");
        System.out.println(RegexGroupUtils.findParams(pattern, line1).toString());
        System.out.println("-----line2--------");
        System.out.println(RegexGroupUtils.findParams(pattern, line2).toString());
        //-----------end 測試匹配 uuid(32-36位)

        //-----------start 測試匹配 ip(下划線分割)
        System.out.println("----------------IP------------");
        String lineIp = "summarize(clm.pm.xxx.yyy.uuu.zzz.10_144_202_141.agg.cpu.percent-avg.system,'10min','avg'," +
                "true)";
        String patternIp = "^.*clm\\.(?<type>\\w+\\.*.*)\\.(?<hostId>\\d{0,3}_\\d{0,3}_\\d{0,3}_\\d{0,3})";
        System.out.println(RegexGroupUtils.findParams(patternIp, lineIp).toString());
        //-----------start 測試匹配 ip(下划線分割)
    }
    /**
     * 輸出:
     *
     * -----line1--------
     * {hostId=0193f1b3-7bcc-4374-8546-8e87b7276003, type=pm.xxx.yyy.uuu.zzz}
     * -----line2--------
     * {hostId=0193f1b3-7bcc-4374-8546-8e87b7276003, type=pm}
     * ----------------IP------------
     * {hostId=10_144_202_141, type=pm.xxx.yyy.uuu.zzz}
     */
}

相關鏈接

【占位符替換】替換String中的占位符標志位{placeholder}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM