Java 9中的新Regex功能
最近,我收到了Packt出版的Anubhava Srivastava提供的免費書籍“ Java 9 Regular Expressions” 。 這本書是一個很好的教程,它向任何想學習正則表達式并從頭開始的人介紹。 那些知道如何使用正則表達式的人可能仍然很有趣,以重申其知識并加深諸如零長度斷言,反向引用之類的復雜特征。
在本文中,我將重點介紹特定于Java 9且在早期版本的JDK中不可用的正則表達式功能。 雖然沒有很多。
Java 9正則表達式模塊
Java 9中的JDK分為多個模塊。 可以理所當然地期望為正則表達式處理包和類提供一個新模塊。 其實沒有。 模塊java.base是默認模塊,默認情況下所有其他模塊都依賴該模塊,因此,導出的包的類在Java應用程序中始終可用。 此模塊導出正則表達式包java.util.regex 。 這使開發過程更加簡單:如果我們想在代碼中使用正則表達式,則無需顯式地“要求”模塊。 似乎正則表達式對于Java是如此重要,以至于它包含在基本模塊中。
正則表達式類
包java.util.regex包含這些類
- MatchResult
- Matcher
- Pattern和
- PatternSyntaxException
更改API的唯一類是Matcher 。
類匹配器的變化
Matcher類添加了五個新方法。 其中四個是現有方法的重載版本。 這些是:
- appendReplacement
- appendTail?
- replaceAll?
- replaceFirst?
- results?
前四個存在于較早的版本中,并且參數的類型僅發生變化(畢竟這就是重載的意思)。
appendReplacement / Tail
對于appendReplacement和appendTail ,唯一的區別是該參數還可以是StringBuilder ,而不僅僅是StringBuffer 。 考慮到StringBuilder是Java 1.5中引入的,就像13年前一樣,沒有人可以說這是一個不明智的行為。
有趣的是,API JDK的當前在線版本如何記錄StringBuilder參數的appendReplacement行為。 較舊的StringBuffer變量方法顯式記錄了替換字符串可能包含將由相應組替換的命名引用。 StringBuilder論據版本錯過了這一點。 該文檔似乎像復制/粘貼然后進行編輯。 文本將“ buffer”替換為“ builder”等,并刪除記錄命名參考功能的文本。
我使用Java 9 build160嘗試了該功能,對于這兩個方法版本,結果是相同的。 這并不奇怪,因為這兩種方法的源代碼是相同的,除了參數類型之外,在JDK中都是簡單的復制/粘貼。
似乎可以使用
@Testpublic void testAppendReplacement() {Pattern p = Pattern.compile("cat(?<plural>z?s?)");//Pattern p = Pattern.compile("cat(z?s?)");Matcher m = p.matcher("one catz two cats in the yard");StringBuilder sb = new StringBuilder();while (m.find()) {m.appendReplacement(sb, "dog${plural}");//m.appendReplacement(sb, "dog$001");}m.appendTail(sb);String result = sb.toString();assertEquals("one dogz two dogs in the yard", result);}注釋行或每行上方的行。 但是,文檔僅涉及編號參考。
replaceAll / First
這也是一種“舊的”方法,用一些新的字符串替換匹配的組。 舊版本和新版本之間的唯一區別是替換字符串的提供方式。 在老版本的字符串被賦予作為String調用方法之前計算。 在新版本中,字符串作為Function<MatchResult,String> 。 將為每個匹配結果調用此函數,并且可以動態計算替換字符串。
知道Function類是3年前才在Java 8中引入的,因此在正則表達式中對它的新使用可能有點破綻。 或者,也許……也許我們應該將其視為一個提示,即從現在開始十年,當Fuction類已經13歲時,我們仍將擁有Java 9?
讓我們更深入地研究這兩種方法。 (實際上只用于replaceAll因為replaceFirst相同,只不過它只替換第一個匹配的組。)當這種用法很有價值時,我嘗試創建一些并非絕對復雜的示例。
第一個示例來自JDK文檔:
@Testpublic void demoReplaceAllFunction() {Pattern pattern = Pattern.compile("dog");Matcher matcher = pattern.matcher("zzzdogzzzdogzzz");String result = matcher.replaceAll(mr -> mr.group().toUpperCase());assertEquals("zzzDOGzzzDOGzzz", result);}它不太復雜,并顯示了功能。 使用lambda表達式絕對足夠。 我無法想象一種簡單的方法將常量字符串文字“ dog”大寫。 也許只寫“ DOG”。 好吧,我只是在開玩笑。 但是實際上這個例子太簡單了。 對于文檔來說是可以的,更復雜的事情會使讀者分心于所記錄方法的功能。 確實:不要期望JavaDoc中的復雜示例更少。 它描述了如何使用API??,而不是描述了為何以這種方式創建API。
但是現在我們現在將看一些更復雜的例子。 我們要在字符串中用數字1、2、3等替換#字符。 該字符串包含編號的項目,如果我們在該字符串中插入一個新項目,我們不想手動重新編號。 有時我們將兩個項目組合在一起,在這種情況下,我們編寫## ,然后只想跳過下一個#的序列號。 由于我們已經進行了單元測試,因此代碼比我可以用語言更好地描述了功能:
@Testpublic void countSampleReplaceAllFunction() {AtomicInteger counter = new AtomicInteger(0);Pattern pattern = Pattern.compile("#+");Matcher matcher = pattern.matcher("# first item\n" +"# second item\n" +"## third and fourth\n" +"## item 5 and 6\n" +"# item 7");String result = matcher.replaceAll(mr -> "" + counter.addAndGet(mr.group().length()));assertEquals("1 first item\n" +"2 second item\n" +"4 third and fourth\n" +"6 item 5 and 6\n" +"7 item 7", result);}
傳遞給replaceAll的lambda表達式獲取計數器并計算下一個值。 如果我們使用一個#那么如果我們使用兩個,它將增加1,然后將其添加到計數器,依此類推。 因為lambda表達式不能在周圍環境中更改變量的值(變量必須有效地為final),所以計數器不能為int或Integer變量。 我們需要一個具有int值并且可以更改的對象。 即使我們不使用AtomicInteger的原子功能,它也是如此。
下一個示例更進一步,并進行了一些數學計算。 它將字符串中的任何浮點格式的數字替換為其正弦值。 這樣,由于sin(pi)甚至與pi都不接近,因此它可以糾正我們的句子,此處無法精確表示。 它幾乎接近零:
@Testpublic void calculateSampleReplaceAllFunction() {Pattern pattern = Pattern.compile("\\d+(?:\\.\\d+)?(?:[Ee][+-]?\\d{1,2})?");Matcher matcher = pattern.matcher("The sin(pi) is 3.1415926");String result = matcher.replaceAll(mr -> "" + (Math.sin(Double.parseDouble(mr.group()))));assertEquals("The sin(pi) is 5.3589793170057245E-8", result);}我們還將對此計算進行一些操作,以演示列表中的最后一個方法,它是Matcher類中的一個全新方法。
流結果()
新方法results()返回匹配結果流。 更精確地說,它返回MatchResult對象的Stream 。 在下面的示例中,我們使用它從字符串中收集任何浮點格式的數字,并以逗號分隔打印其正弦值:
@Testpublic void resultsTest() {Pattern pattern = Pattern.compile("\\d+(?:\\.\\d+)?(?:[Ee][+-]?\\d{1,2})?");Matcher matcher = pattern.matcher("Pi is around 3.1415926 and not 3.2 even in Indiana");String result = String.join(",",matcher.results().map(mr -> "" + (Math.sin(Double.parseDouble(mr.group())))).collect(Collectors.toList()));assertEquals("5.3589793170057245E-8,-0.058374143427580086", result);}摘要
Java 9 JDK中引入的新正則表達式方法與現有的方法沒有本質上的區別。 它們整潔方便,在某些情況下可以簡化編程。 在早期版本中沒有沒有引入的任何內容。 這只是Java緩慢而深思熟慮地對JDK進行此類更改的方式。 畢竟,這就是我們愛Java的原因,不是嗎?
可以從以下要點中找到并下載IDE中的整個代碼副本粘貼
翻譯自: https://www.javacodegeeks.com/2017/08/new-regex-features-java-9.html
總結
以上是生活随笔為你收集整理的Java 9中的新Regex功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ddos拒绝服务攻击特点有哪些(ddos
- 下一篇: linux网络服务启动失败(linux