Die Denklogik von Computerprogrammen (89) – Reguläre Ausdrücke (mittel)
上节介绍了正则表达式的语法,本节介绍相关的Java API。
正则表达式相关的类位于包java.util.regex下,有两个主要的类,一个是Pattern,另一个是Matcher。Pattern表示正则表达式对象,它与要处理的具体字符串无关。Matcher表示一个匹配,它将正则表达式应用于一个具体字符串,通过它对字符串进行处理。
字符串类String也是一个重要的类,我们在29节专门介绍过String,其中提到,它有一些方法,接受的参数不是普通的字符串,而是正则表达式。此外,正则表达式在Java中是需要先以字符串形式表示的。
下面,我们先来介绍如何表示正则表达式,然后探讨如何利用它实现一些常见的文本处理任务,包括切分、验证、查找、和替换。
表示正则表达式
转义符 '\'
正则表达式由元字符和普通字符组成,字符'\'是一个元字符,要在正则表达式中表示'\'本身,需要使用它转义,即'\\'。
在Java中,没有什么特殊的语法能直接表示正则表达式,需要用字符串表示,而在字符串中,'\'也是一个元字符,为了在字符串中表示正则表达式的'\',就需要使用两个'\',即'\\',而要匹配'\'本身,就需要四个'\',即'\\\\',比如说,如下表达式:
<(\w+)>(.*)</\1>
对应的字符串表示就是:
"<(\\w+)>(.*)</\\1>"
一个简单规则是,正则表达式中的任何一个'\',在字符串中,需要替换为两个'\'。
Pattern对象
字符串表示的正则表达式可以被编译为一个Pattern对象,比如:
String regex = "<(\\w+)>(.*)</\\1>"; Pattern pattern = Pattern.compile(regex);
Pattern是正则表达式的面向对象表示,所谓编译,简单理解就是将字符串表示为了一个内部结构,这个结构是一个有穷自动机,关于有穷自动机的理论比较深入,我们就不探讨了。
编译有一定的成本,而且Pattern对象只与正则表达式有关,与要处理的具体文本无关,它可以安全地被多线程共享,所以,在使用同一个正则表达式处理多个文本时,应该尽量重用同一个Pattern对象,避免重复编译。
匹配模式
Pattern的compile方法接受一个额外参数,可以指定匹配模式:
public static Pattern compile(String regex, int flags)
上节,我们介绍过三种匹配模式:单行模式(点号模式)、多行模式和大小写无关模式,它们对应的常量分别为:Pattern.DOTALL,Pattern.MULTILINE和Pattern.CASE_INSENSITIVE,多个模式可以一起使用,通过'|'连起来即可,如下所示:
Pattern.compile(regex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL)
还有一个模式Pattern.LITERAL,在此模式下,正则表达式字符串中的元字符将失去特殊含义,被看做普通字符。Pattern有一个静态方法:
public static String quote(String s)
quote()的目的是类似的,它将s中的字符都看作普通字符。我们在上节介绍过\Q和\E,\Q和\E之间的字符会被视为普通字符。quote()基本上就是在字符串s的前后加了\Q和\E,比如,如果s为"\\d{6}",则quote()的返回值就是"\\Q\\d{6}\\E"。
切分
简单情况
文本处理的一个常见需求是根据分隔符切分字符串,比如在处理CSV文件时,按逗号分隔每个字段,这个需求听上去很容易满足,因为String类有如下方法:
public String[] split(String regex)
比如:
String str = "abc,def,hello"; String[] fields = str.split(","); System.out.println("field num: "+fields.length); System.out.println(Arrays.toString(fields));
输出为:
field num: 3[abc, def, hello]
不过,有一些重要的细节,我们需要注意。
转义元字符
split将参数regex看做正则表达式,而不是普通的字符,如果分隔符是元字符,比如. $ | ( ) [ { ^ ? * + \,就需要转义,比如按点号'.'分隔,就需要写为:
String[] fields = str.split("\\.");
如果分隔符是用户指定的,程序事先不知道,可以通过Pattern.quote()将其看做普通字符串。
将多个字符用作分隔符
既然是正则表达式,分隔符就不一定是一个字符,比如,可以将一个或多个空白字符或点号作为分隔符,如下所示:
String str = "abc def hello.\n world"; String[] fields = str.split("[\\s.]+");
fields内容为:
[abc, def, hello, world]
空白字符串
需要说明的是,尾部的空白字符串不会包含在返回的结果数组中,但头部和中间的空白字符串会被包含在内,比如:
String str = ",abc,,def,,"; String[] fields = str.split(","); System.out.println("field num: "+fields.length); System.out.println(Arrays.toString(fields));
输出为:
field num: 4[, abc, , def]
找不到分隔符
如果字符串中找不到匹配regex的分隔符,返回数组长度为1,元素为原字符串。
切分数目限制
split方法接受一个额外的参数limit,用于限定切分的数目:
public String[] split(String regex, int limit)
不带limit参数的split,其limit相当于0。关于limit的含义,我们通过一个例子说明下,比如字符串是"a:b:c:",分隔符是":",在limit为不同值的情况下,其返回数组如下表所示:
Pattern的split方法
Pattern也有两个split方法,与String方法的定义类似:
public String[] split(CharSequence input)public String[] split(CharSequence input, int limit)
与String方法的区别是:
Pattern接受的参数是CharSequence,更为通用,我们知道String, StringBuilder, StringBuffer, CharBuffer等都实现了该接口;
如果regex长度大于1或包含元字符,String的split方法会先将regex编译为Pattern对象,再调用Pattern的split方法,这时,为避免重复编译,应该优先采用Pattern的方法;
如果regex就是一个字符且不是元字符,String的split方法会采用更为简单高效的实现,所以,这时,应该优先采用String的split方法。
验证
验证就是检验输入文本是否完整匹配预定义的正则表达式,经常用于检验用户的输入是否合法。
String有如下方法:
public boolean matches(String regex)
比如:
String regex = "\\d{8}"; String str = "12345678"; System.out.println(str.matches(regex));
检查输入是否是8位数字,输出为true。
String的matches实际调用的是Pattern的如下方法:
public static boolean matches(String regex, CharSequence input)
这是一个静态方法,它的代码为:
public static boolean matches(String regex, CharSequence input) { Pattern p = Pattern.compile(regex); Matcher m = p.matcher(input);return m.matches(); }
就是先调用compile编译regex为Pattern对象,再调用Pattern的matcher方法生成一个匹配对象Matcher,Matcher的matches()返回是否完整匹配。
查找
查找就是在文本中寻找匹配正则表达式的子字符串,看个例子:
public static void find(){ String regex = "\\d{4}-\\d{2}-\\d{2}"; Pattern pattern = Pattern.compile(regex); String str = "today is 2017-06-02, yesterday is 2017-06-01"; Matcher matcher = pattern.matcher(str);while(matcher.find()){ System.out.println("find "+matcher.group()+" position: "+matcher.start()+"-"+matcher.end()); } }
代码寻找所有类似"2017-06-02"这种格式的日期,输出为:
find 2017-06-02 position: 9-19find 2017-06-01 position: 34-44
Matcher的内部记录有一个位置,起始为0,find()方法从这个位置查找匹配正则表达式的子字符串,找到后,返回true,并更新这个内部位置,匹配到的子字符串信息可以通过如下方法获取:
//匹配到的完整子字符串public String group()//子字符串在整个字符串中的起始位置public int start()//子字符串在整个字符串中的结束位置加1public int end()
group()其实调用的是group(0),表示获取匹配的第0个分组的内容。我们在上节介绍过捕获分组的概念,分组0是一个特殊分组,表示匹配的整个子字符串。除了分组0,Matcher还有如下方法,获取分组的更多信息:
//分组个数public int groupCount()//分组编号为group的内容public String group(int group)//分组命名为name的内容public String group(String name)//分组编号为group的起始位置public int start(int group)//分组编号为group的结束位置加1public int end(int group)
比如:
public static void findGroup() { String regex = "(\\d{4})-(\\d{2})-(\\d{2})"; Pattern pattern = Pattern.compile(regex); String str = "today is 2017-06-02, yesterday is 2017-06-01"; Matcher matcher = pattern.matcher(str);while (matcher.find()) { System.out.println("year:" + matcher.group(1)+ ",month:" + matcher.group(2)+ ",day:" + matcher.group(3)); } }
输出为:
year:2017,month:06,day:02year:2017,month:06,day:01
替换
replaceAll和replaceFirst
查找到子字符串后,一个常见的后续操作是替换。String有多个替换方法:
public String replace(char oldChar, char newChar)public String replace(CharSequence target, CharSequence replacement)public String replaceAll(String regex, String replacement)public String replaceFirst(String regex, String replacement)
第一个replace方法操作的是单个字符,第二个是CharSequence,它们都是将参数看做普通字符。而replaceAll和replaceFirst则将参数regex看做正则表达式,它们的区别是,replaceAll替换所有找到的子字符串,而replaceFirst则只替换第一个找到的,看个简单的例子,将字符串中的多个连续空白字符替换为一个:
String regex = "\\s+"; String str = "hello world good"; System.out.println(str.replaceAll(regex, " "));
输出为:
hello world good
在replaceAll和replaceFirst中,参数replacement也不是被看做普通的字符串,可以使用美元符号加数字的形式,比如$1,引用捕获分组,我们看个例子:
String regex = "(\\d{4})-(\\d{2})-(\\d{2})"; String str = "today is 2017-06-02."; System.out.println(str.replaceFirst(regex, "$1/$2/$3"));
输出为:
today is 2017/06/02.
这个例子将找到的日期字符串的格式进行了转换。所以,字符'$'在replacement中是元字符,如果需要替换为字符'$'本身,需要使用转义,看个例子:
String regex = "#"; String str = "#this is a test"; System.out.println(str.replaceAll(regex, "\\$"));
如果替换字符串是用户提供的,为避免元字符的的干扰,可以使用Matcher的如下静态方法将其视为普通字符串:
public static String quoteReplacement(String s)
String的replaceAll和replaceFirst调用的其实是Pattern和Matcher中的方法,比如,replaceAll的代码为:
public String replaceAll(String regex, String replacement) {return Pattern.compile(regex).matcher(this).replaceAll(replacement); }
边查找边替换
replaceAll和replaceFirst都定义在Matcher中,除了一次性的替换操作外,Matcher还定义了边查找、边替换的方法:
public Matcher appendReplacement(StringBuffer sb, String replacement)public StringBuffer appendTail(StringBuffer sb)
这两个方法用于和find()一起使用,我们先看个例子:
public static void replaceCat() { Pattern p = Pattern.compile("cat"); Matcher m = p.matcher("one cat, two cat, three cat"); StringBuffer sb = new StringBuffer();int foundNum = 0;while (m.find()) { m.appendReplacement(sb, "dog"); foundNum++;if (foundNum == 2) {break; } } m.appendTail(sb); System.out.println(sb.toString()); }
在这个例子中,我们将前两个"cat"替换为了"dog",其他"cat"不变,输出为:
one dog, two dog, three cat
StringBuffer类型的变量sb存放最终的替换结果,Matcher内部除了有一个查找位置,还有一个append位置,初始为0,当找到一个匹配的子字符串后,appendReplacement()做了三件事情:
将append位置到当前匹配之前的子字符串append到sb中,在第一次操作中,为"one ",第二次为", two ";
将替换字符串append到sb中;
更新append位置为当前匹配之后的位置。
appendTail将append位置之后所有的字符append到sb中。
模板引擎
利用Matcher的这几个方法,我们可以实现一个简单的模板引擎,模板是一个字符串,中间有一些变量,以{name}表示,如下例所示:
String template = "Hi {name}, your code is {code}.";
这里,模板字符串中有两个变量,一个是name,另一个是code。变量的实际值通过Map提供,变量名称对应Map中的键,模板引擎的任务就是接受模板和Map作为参数,返回替换变量后的字符串,示例实现为:
private static Pattern templatePattern = Pattern.compile("\\{(\\w+)\\}");public static String templateEngine(String template, Map<String, Object> params) { StringBuffer sb = new StringBuffer(); Matcher matcher = templatePattern.matcher(template);while (matcher.find()) { String key = matcher.group(1); Object value = params.get(key); matcher.appendReplacement(sb, value != null ?Matcher.quoteReplacement(value.toString()) : ""); } matcher.appendTail(sb);return sb.toString(); }
代码寻找所有的模板变量,正则表达式为:
\{(\w+)\}
'{'是元字符,所以要转义,\w+表示变量名,为便于引用,加了括号,可以通过分组1引用变量名。
使用该模板引擎的示例代码为:
public static void templateDemo() { String template = "Hi {name}, your code is {code}."; Mapparams = new HashMap (); params.put("name", "老马"); params.put("code", 6789); System.out.println(templateEngine(template, params)); }
输出为:
Hi 老马, your code is 6789.
小结
本节介绍了正则表达式相关的主要Java API,讨论了如何在Java中表示正则表达式,如何利用它实现文本的切分、验证、查找和替换,对于替换,我们演示了一个简单的模板引擎。
下一节,我们继续探讨正则表达式,讨论和分析一些常见的正则表达式。
Das obige ist der detaillierte Inhalt vonDie Denklogik von Computerprogrammen (89) – Reguläre Ausdrücke (mittel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Die Standardkarte auf dem iPhone ist Maps, Apples proprietärer Geolokalisierungsanbieter. Obwohl die Karte immer besser wird, funktioniert sie außerhalb der Vereinigten Staaten nicht gut. Im Vergleich zu Google Maps hat es nichts zu bieten. In diesem Artikel besprechen wir die möglichen Schritte, um Google Maps als Standardkarte auf Ihrem iPhone zu nutzen. So machen Sie Google Maps zur Standardkarte auf dem iPhone. Das Festlegen von Google Maps als Standardkarten-App auf Ihrem Telefon ist einfacher als Sie denken. Befolgen Sie die nachstehenden Schritte – Erforderliche Schritte – Sie müssen Gmail auf Ihrem Telefon installiert haben. Schritt 1 – Öffnen Sie den AppStore. Schritt 2 – Suchen Sie nach „Gmail“. Schritt 3 – Klicken Sie auf neben der Gmail-App

Die 2024CSRankings National Computer Science Major Rankings wurden gerade veröffentlicht! In diesem Jahr gehört die Carnegie Mellon University (CMU) im Ranking der besten CS-Universitäten in den Vereinigten Staaten zu den Besten des Landes und im Bereich CS, während die University of Illinois at Urbana-Champaign (UIUC) einen der besten Plätze belegt sechs Jahre in Folge den zweiten Platz belegt. Georgia Tech belegte den dritten Platz. Dann teilten sich die Stanford University, die University of California in San Diego, die University of Michigan und die University of Washington den vierten Platz weltweit. Es ist erwähnenswert, dass das Ranking des MIT zurückgegangen ist und aus den Top 5 herausgefallen ist. CSRankings ist ein globales Hochschulrankingprojekt im Bereich Informatik, das von Professor Emery Berger von der School of Computer and Information Sciences der University of Massachusetts Amherst initiiert wurde. Die Rangfolge erfolgt objektiv

Mit dem Windows-Remotedesktopdienst können Benutzer aus der Ferne auf Computer zugreifen, was für Personen, die aus der Ferne arbeiten müssen, sehr praktisch ist. Es können jedoch Probleme auftreten, wenn Benutzer keine Verbindung zum Remotecomputer herstellen können oder Remotedesktop die Identität des Computers nicht authentifizieren kann. Dies kann durch Netzwerkverbindungsprobleme oder einen Fehler bei der Zertifikatsüberprüfung verursacht werden. In diesem Fall muss der Benutzer möglicherweise die Netzwerkverbindung überprüfen, sicherstellen, dass der Remote-Computer online ist, und versuchen, die Verbindung wiederherzustellen. Außerdem ist es wichtig, sicherzustellen, dass die Authentifizierungsoptionen des Remotecomputers richtig konfiguriert sind, um das Problem zu lösen. Solche Probleme mit den Windows-Remotedesktopdiensten können normalerweise durch sorgfältiges Überprüfen und Anpassen der Einstellungen behoben werden. Aufgrund eines Zeit- oder Datumsunterschieds kann Remote Desktop die Identität des Remotecomputers nicht überprüfen. Bitte stellen Sie Ihre Berechnungen sicher

Gelegentlich kann es bei der Verwendung eines Computers zu Fehlfunktionen des Betriebssystems kommen. Das Problem, auf das ich heute gestoßen bin, bestand darin, dass das System beim Zugriff auf gpedit.msc mitteilte, dass das Gruppenrichtlinienobjekt nicht geöffnet werden könne, weil möglicherweise die richtigen Berechtigungen fehlten. Das Gruppenrichtlinienobjekt auf diesem Computer konnte nicht geöffnet werden: 1. Beim Zugriff auf gpedit.msc meldet das System, dass das Gruppenrichtlinienobjekt auf diesem Computer aufgrund fehlender Berechtigungen nicht geöffnet werden kann. Details: Das System kann den angegebenen Pfad nicht finden. 2. Nachdem der Benutzer auf die Schaltfläche „Schließen“ geklickt hat, wird das folgende Fehlerfenster angezeigt. 3. Überprüfen Sie sofort die Protokolleinträge und kombinieren Sie die aufgezeichneten Informationen, um festzustellen, dass das Problem in der Datei C:\Windows\System32\GroupPolicy\Machine\registry.pol liegt

Fehlt die Uhr-App auf Ihrem Telefon? Datum und Uhrzeit werden weiterhin in der Statusleiste Ihres iPhones angezeigt. Ohne die Uhr-App können Sie jedoch die Weltzeituhr, die Stoppuhr, den Wecker und viele andere Funktionen nicht nutzen. Daher sollte die Reparatur der fehlenden Uhr-App ganz oben auf Ihrer To-Do-Liste stehen. Diese Lösungen können Ihnen bei der Lösung dieses Problems helfen. Lösung 1 – Platzieren Sie die Uhr-App. Wenn Sie versehentlich die Uhr-App von Ihrem Startbildschirm entfernt haben, können Sie die Uhr-App wieder an ihrem Platz platzieren. Schritt 1 – Entsperren Sie Ihr iPhone und wischen Sie nach links, bis Sie zur Seite „App-Bibliothek“ gelangen. Schritt 2 – Suchen Sie als Nächstes im Suchfeld nach „Uhr“. Schritt 3 – Wenn Sie unten in den Suchergebnissen „Uhr“ sehen, halten Sie die Taste und gedrückt

C++ ist eine weit verbreitete Programmiersprache, die sich beim Schreiben von Countdown-Programmen sehr praktisch und praktisch eignet. Das Countdown-Programm ist eine gängige Anwendung, die uns sehr genaue Zeitberechnungs- und Countdown-Funktionen bieten kann. In diesem Artikel wird erläutert, wie Sie mit C++ ein einfaches Countdown-Programm schreiben. Der Schlüssel zur Implementierung eines Countdown-Programms besteht darin, einen Timer zur Berechnung des Zeitablaufs zu verwenden. In C++ können wir die Funktionen in der Header-Datei time.h verwenden, um die Timer-Funktion zu implementieren. Das Folgende ist der Code für ein einfaches Countdown-Programm

Besuchen Sie häufig dieselbe Website jeden Tag etwa zur gleichen Zeit? Dies kann dazu führen, dass Sie viel Zeit mit mehreren geöffneten Browser-Registerkarten verbringen und den Browser bei der Ausführung täglicher Aufgaben überladen. Wie wäre es, wenn Sie es öffnen, ohne den Browser manuell starten zu müssen? Es ist sehr einfach und erfordert nicht das Herunterladen von Apps von Drittanbietern, wie unten gezeigt. Wie richte ich den Taskplaner ein, um eine Website zu öffnen? Drücken Sie die Taste, geben Sie „Taskplaner“ in das Suchfeld ein und klicken Sie dann auf „Öffnen“. Klicken Sie in der rechten Seitenleiste auf die Option „Basisaufgabe erstellen“. Geben Sie im Feld „Name“ den Namen der Website ein, die Sie öffnen möchten, und klicken Sie auf „Weiter“. Klicken Sie anschließend unter „Trigger“ auf „Zeitfrequenz“ und dann auf „Weiter“. Wählen Sie aus, wie lange das Ereignis wiederholt werden soll, und klicken Sie auf „Weiter“. Wählen Sie „Aktivieren“.

In iOS 17 hat Apple nicht nur mehrere neue Messaging-Funktionen hinzugefügt, sondern auch das Design der Nachrichten-App optimiert, um ihr ein klareres Aussehen zu verleihen. Auf alle iMessage-Apps und -Tools, wie z. B. die Kamera- und Fotooptionen, kann jetzt zugegriffen werden, indem man auf die Schaltfläche „+“ über der Tastatur und links neben dem Texteingabefeld tippt. Wenn Sie auf die Schaltfläche „+“ klicken, wird eine Menüspalte mit einer Standardreihenfolge der Optionen angezeigt. Von oben beginnend gibt es Kamera, Fotos, Aufkleber, Bargeld (falls verfügbar), Audio und Standort. Ganz unten befindet sich die Schaltfläche „Mehr“, die beim Antippen alle anderen installierten Messaging-Apps anzeigt (Sie können auch nach oben wischen, um diese versteckte Liste anzuzeigen). So organisieren Sie Ihre iMessage-App neu. Dies können Sie unten tun
