正則表達式匹配不包含指定字符串的文本實例演示
前言
在日常的文本處理、數(shù)據(jù)篩選場景中,我們經(jīng)常需要反向匹配——找出不包含某個特定字符串的文本內(nèi)容。正則表達式本身擅長“匹配存在的內(nèi)容”,但通過“負向環(huán)視”特性,我們可以輕松實現(xiàn)這一反向需求。
原理:負向環(huán)視(Negative Lookahead)
要匹配不包含指定字符串(如 target)的文本,核心正則表達式如下:
^(?!.*target).*$
表達式逐部分解析
| 表達式片段 | 具體含義 |
|---|---|
^ | 匹配字符串的開頭位置,確保從文本最起始處開始檢查 |
(?!.*target) | 負向環(huán)視(負向前瞻斷言): - ?! 表示“斷言當前位置后不存在指定模式”;- .* 匹配任意字符(除換行符外,單行模式除外)任意次數(shù);- 整體作用:從開頭位置檢查,確保后續(xù)所有內(nèi)容中都找不到 target |
.* | 匹配符合“不包含 target”條件的任意字符(除換行符)任意次數(shù),即文本主體內(nèi)容 |
$ | 匹配字符串的結(jié)尾位置,確保檢查覆蓋到文本末尾 |
效果:該表達式僅匹配“從開頭到結(jié)尾完整、且全程不包含 target”的字符串,只要文本中出現(xiàn) target,匹配立即失敗。
實例演示
PHP 示例
<?php
// 待處理的多行文本(包含換行的跨行文內(nèi)容)
$text = "
hello world
test target 123
php regex demo
這是跨換行的內(nèi)容
foo target bar
no match here
";
// 場景1:僅按行匹配(不跨換行)
echo "=== 場景1:僅按行匹配(不跨換行)===\n";
$regex1 = '/^(?!.*target).*$/m';
preg_match_all($regex1, $text, $matches1);
foreach ($matches1[0] as $match) {
$match = trim($match);
if ($match !== "") {
echo $match . "\n";
}
}
// 場景2:跨換行匹配整段內(nèi)容(/s 開啟單行模式)
echo "\n=== 場景2:跨換行匹配整段內(nèi)容 ===\n";
$regex2 = '/^(?!.*target).*$/s';
// 用 preg_match 匹配整段,而非 preg_match_all
$isFullMatch = preg_match($regex2, $text);
if (!$isFullMatch) {
echo "整段文本包含 target,匹配失敗\n";
}
// 測試無 target 的跨行文本
$textNoTarget = "
hello php
這是跨換行的內(nèi)容
無 target 字符串
";
$isNoTargetMatch = preg_match($regex2, $textNoTarget);
if ($isNoTargetMatch) {
echo "\n無 target 的跨行文本匹配結(jié)果:\n";
echo trim($textNoTarget) . "\n";
}
?>
運行結(jié)果:
=== 場景1:僅按行匹配(不跨換行)=== hello world php regex demo 這是跨換行的內(nèi)容 no match here === 場景2:跨換行匹配整段內(nèi)容 === 整段文本包含 target,匹配失敗 無 target 的跨行文本匹配結(jié)果: hello php 這是跨換行的內(nèi)容 無 target 字符串
Java 示例
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexNoTarget {
public static void main(String[] args) {
// 待處理的多行文本(包含換行的跨行文內(nèi)容)
String text = """
hello world
test target 123
java regex demo
這是跨換行的內(nèi)容
foo target bar
no match here
""";
// 場景1:僅按行匹配(不跨換行)
System.out.println("=== 場景1:僅按行匹配(不跨換行)===");
String regex1 = "^(?!.*target).*$";
Pattern pattern1 = Pattern.compile(regex1, Pattern.MULTILINE);
Matcher matcher1 = pattern1.matcher(text);
while (matcher1.find()) {
String match = matcher1.group().trim();
if (!match.isEmpty()) {
System.out.println(match);
}
}
// 場景2:跨換行匹配整段內(nèi)容(開啟 DOTALL)
System.out.println("\n=== 場景2:跨換行匹配整段內(nèi)容 ===");
String regex2 = "^(?!.*target).*$";
Pattern pattern2 = Pattern.compile(regex2, Pattern.DOTALL);
Matcher matcher2 = pattern2.matcher(text);
if (matcher2.matches()) {
System.out.println(matcher2.group());
} else {
System.out.println("整段文本包含 target,匹配失敗");
}
// 測試無 target 的跨行文本
String textNoTarget = """
hello java
這是跨換行的內(nèi)容
無 target 字符串
""";
Matcher matcher3 = pattern2.matcher(textNoTarget);
if (matcher3.matches()) {
System.out.println("\n無 target 的跨行文本匹配結(jié)果:");
System.out.println(matcher3.group().trim());
}
}
}
運行結(jié)果:
=== 場景1:僅按行匹配(不跨換行)=== hello world java regex demo 這是跨換行的內(nèi)容 no match here === 場景2:跨換行匹配整段內(nèi)容 === 整段文本包含 target,匹配失敗 無 target 的跨行文本匹配結(jié)果: hello java 這是跨換行的內(nèi)容 無 target 字符串
Go 示例
package main
import (
"fmt"
"regexp"
"strings"
)
func main() {
// 待處理的多行文本(包含換行的跨行文內(nèi)容)
text := `
hello world
test target 123
golang regex demo
這是跨換行的內(nèi)容
foo target bar
no match here
`
// 場景1:僅按行匹配(不跨換行)
fmt.Println("=== 場景1:僅按行匹配(不跨換行)===")
regex1 := regexp.MustCompile(`(?m)^(?!.*target).*$`)
matches1 := regex1.FindAllString(text, -1)
for _, match := range matches1 {
match = strings.TrimSpace(match)
if match != "" {
fmt.Println(match)
}
}
// 場景2:跨換行匹配整段內(nèi)容((?s) 開啟單行模式)
fmt.Println("\n=== 場景2:跨換行匹配整段內(nèi)容 ===")
regex2 := regexp.MustCompile(`(?s)^(?!.*target).*$`)
// 用 MatchString 判斷整段是否匹配,更嚴謹
isFullMatch := regex2.MatchString(text)
if !isFullMatch {
fmt.Println("整段文本包含 target,匹配失敗")
}
// 測試無 target 的跨行文本
textNoTarget := `
hello golang
這是跨換行的內(nèi)容
無 target 字符串
`
isNoTargetMatch := regex2.MatchString(textNoTarget)
if isNoTargetMatch {
fmt.Println("\n無 target 的跨行文本匹配結(jié)果:")
fmt.Println(strings.TrimSpace(textNoTarget))
}
}
運行結(jié)果:
=== 場景1:僅按行匹配(不跨換行)=== hello world golang regex demo 這是跨換行的內(nèi)容 no match here === 場景2:跨換行匹配整段內(nèi)容 === 整段文本包含 target,匹配失敗 無 target 的跨行文本匹配結(jié)果: hello golang 這是跨換行的內(nèi)容 無 target 字符串
JavaScript 示例
// 待處理的多行文本
const text = `
hello world
test target 123
javascript regex demo
這是跨換行的內(nèi)容
foo target bar
no match here
`;
// 無 target 的跨行測試文本
const textNoTarget = `
hello javascript
這是跨換行的內(nèi)容
無 target 字符串
`;
// 場景1:僅按行匹配(開啟多行模式 m)
console.log("=== 場景1:僅按行匹配(不跨換行)===");
const regex1 = /^(?!.*target).*$/m;
// 用 match 直接提取所有匹配行,更簡潔
const matches1 = text.match(regex1) || [];
matches1.forEach(line => {
const trimmed = line.trim();
if (trimmed) {
console.log(trimmed);
}
});
// 場景2:跨換行匹配整段內(nèi)容(開啟單行模式 s)
console.log("\n=== 場景2:跨換行匹配整段內(nèi)容 ===");
const regex2 = /^(?!.*target).*$/s;
if (!regex2.test(text)) {
console.log("整段文本包含 target,匹配失敗");
}
// 匹配無 target 的文本
if (regex2.test(textNoTarget)) {
console.log("\n無 target 的跨行文本匹配結(jié)果:");
console.log(textNoTarget.trim());
}
運行環(huán)境:瀏覽器控制臺/Node.js(v10+ 支持 s 修飾符)
運行結(jié)果:
=== 場景1:僅按行匹配(不跨換行)=== hello world javascript regex demo 這是跨換行的內(nèi)容 no match here === 場景2:跨換行匹配整段內(nèi)容 === 整段文本包含 target,匹配失敗 無 target 的跨行文本匹配結(jié)果: hello javascript 這是跨換行的內(nèi)容 無 target 字符串
C++ 示例
#include <iostream>
#include <regex>
#include <string>
#include <iterator>
#include <algorithm>
// 完善 trim 函數(shù),處理全空白字符串
std::string trim(const std::string& str) {
const std::string whitespace = " \t\n\r";
const size_t start = str.find_first_not_of(whitespace);
if (start == std::string::npos) return ""; // 全空白返回空
const size_t end = str.find_last_not_of(whitespace);
return str.substr(start, end - start + 1);
}
int main() {
// 待處理的多行文本
std::string text =
"\nhello world\n"
"test target 123\n"
"c++ regex demo\n"
"這是跨換行的內(nèi)容\n"
"foo target bar\n"
"no match here\n";
// 無 target 的跨行測試文本
std::string textNoTarget =
"\nhello c++\n"
"這是跨換行的內(nèi)容\n"
"無 target 字符串\n";
// 場景1:僅按行匹配(開啟多行模式)
std::cout << "=== 場景1:僅按行匹配(不跨換行)===" << std::endl;
std::regex regex1("^(?!.*target).*$", std::regex_constants::multiline);
std::sregex_iterator it1(text.begin(), text.end(), regex1);
std::sregex_iterator end1;
for (std::sregex_iterator i = it1; i != end1; ++i) {
std::string match = (*i).str();
std::string trimmed = trim(match);
if (!trimmed.empty()) {
std::cout << trimmed << std::endl;
}
}
// 場景2:跨換行匹配整段內(nèi)容(開啟 dotall 模式)
std::cout << "\n=== 場景2:跨換行匹配整段內(nèi)容 ===" << std::endl;
std::regex regex2("^(?!.*target).*$", std::regex_constants::dotall);
bool isMatch = std::regex_match(text, regex2);
if (!isMatch) {
std::cout << "整段文本包含 target,匹配失敗" << std::endl;
}
// 匹配無 target 的文本
bool isMatchNoTarget = std::regex_match(textNoTarget, regex2);
if (isMatchNoTarget) {
std::cout << "\n無 target 的跨行文本匹配結(jié)果:" << std::endl;
std::cout << trim(textNoTarget) << std::endl;
}
return 0;
}
編譯運行命令:
# 編譯(需支持 C++11 及以上) g++ regex_no_target.cpp -o regex_no_target -std=c++11 # 運行 ./regex_no_target
運行結(jié)果:
=== 場景1:僅按行匹配(不跨換行)=== hello world c++ regex demo 這是跨換行的內(nèi)容 no match here === 場景2:跨換行匹配整段內(nèi)容 === 整段文本包含 target,匹配失敗 無 target 的跨行文本匹配結(jié)果: hello c++ 這是跨換行的內(nèi)容 無 target 字符串
Python 示例
import re
def main():
# 待處理的多行文本(包含換行的跨行文內(nèi)容)
text = """
hello world
test target 123
python regex demo
這是跨換行的內(nèi)容
foo target bar
no match here
"""
# 場景1:僅按行匹配(不跨換行)
print("=== 場景1:僅按行匹配(不跨換行)===")
regex1 = r'^(?!.*target).*$'
# 開啟多行模式 re.M
matches1 = re.findall(regex1, text, re.M)
for match in matches1:
match = match.strip()
if match:
print(match)
# 場景2:跨換行匹配整段內(nèi)容(開啟單行模式 re.S)
print("\n=== 場景2:跨換行匹配整段內(nèi)容 ===")
regex2 = r'^(?!.*target).*$'
# 僅開啟單行模式,匹配整段文本
is_full_match = re.fullmatch(regex2, text, re.S) is not None
if not is_full_match:
print("整段文本包含 target,匹配失敗")
# 測試無 target 的跨行文本
text_no_target = """
hello python
這是跨換行的內(nèi)容
無 target 字符串
"""
is_no_target_match = re.fullmatch(regex2, text_no_target, re.S) is not None
if is_no_target_match:
print("\n無 target 的跨行文本匹配結(jié)果:")
print(text_no_target.strip())
if __name__ == "__main__":
main()運行結(jié)果:
=== 場景1:僅按行匹配(不跨換行)=== hello world python regex demo 這是跨換行的內(nèi)容 no match here === 場景2:跨換行匹配整段內(nèi)容 === 整段文本包含 target,匹配失敗 無 target 的跨行文本匹配結(jié)果: hello python 這是跨換行的內(nèi)容 無 target 字符串
擴展場景
1. 排除多個字符串
若需同時排除 target1 和 target2,只需疊加負向環(huán)視,核心模板如下:
^(?!.*target1)(?!.*target2).*$
Python 示例(匹配不包含 foo 和 bar 的文本)
import re text = "test foo 123\nhello bar 456\npython demo 789" regex = r'^(?!.*foo)(?!.*bar).*$' matches = re.findall(regex, text, re.M) print([m.strip() for m in matches if m.strip()]) # 輸出:['python demo 789']
PHP 示例(匹配不包含 foo 和 bar 的文本)
<?php
$text = "test foo 123\nhello bar 456\nphp demo 789";
$regex = '/^(?!.*foo)(?!.*bar).*$/m';
preg_match_all($regex, $text, $matches);
$result = array_filter(array_map('trim', $matches[0]));
print_r($result); // 輸出:Array ( [2] => php demo 789 )
?>運行結(jié)果:
Array
(
[2] => php demo 789
)Java 示例(匹配不包含 foo 和 bar 的文本)
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExcludeMulti {
public static void main(String[] args) {
String text = "test foo 123\nhello bar 456\njava demo 789";
String regex = "^(?!.*foo)(?!.*bar).*$";
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
String match = matcher.group().trim();
if (!match.isEmpty()) {
System.out.println(match); // 輸出:java demo 789
}
}
}
}
運行結(jié)果:
java demo 789
Go 示例(匹配不包含 foo 和 bar 的文本)
package main
import (
"fmt"
"regexp"
"strings"
)
func main() {
text := "test foo 123\nhello bar 456\ngolang demo 789"
regex := regexp.MustCompile(`(?m)^(?!.*foo)(?!.*bar).*$`)
matches := regex.FindAllString(text, -1)
var result []string
for _, match := range matches {
trimmed := strings.TrimSpace(match)
if trimmed != "" {
result = append(result, trimmed)
}
}
fmt.Println(result) // 輸出:[golang demo 789]
}
運行結(jié)果:
[golang demo 789]
補充說明
- 排除多個字符串的核心邏輯是疊加多個負向環(huán)視斷言,每個
(?!.*目標字符串)對應(yīng)一個需要排除的內(nèi)容; - 多語言實現(xiàn)時僅需保持正則核心不變,調(diào)整模式(如多行模式
m/(?m)/Pattern.MULTILINE)和匹配函數(shù)即可; - 若需排除更多字符串(如 target3、target4),繼續(xù)疊加
(?!.*target3)(?!.*target4)即可,邏輯可無限擴展。
2. 同時開啟多行+單行模式
若需按行匹配跨換行的文本(比如每行內(nèi)容本身包含換行符),可同時開啟兩種模式:
| 語言 | 模式開啟方式(同時開啟多行+單行) | 示例正則 |
|---|---|---|
| PHP | /ms | /^(?!.target).$/ms |
| Java | Pattern.MULTILINE | Pattern.DOTALL | Pattern.compile(“^(?!.target).$”, Pattern.MULTILINE | Pattern.DOTALL) |
| Go | (?ms) | regexp.MustCompile(`(?ms)^(?!.target).$`) |
| JavaScript | /ms | /^(?!.target).$/ms |
| C++ | std::regex_constants::multiline | std::regex_constants::dotall | std::regex(“^(?!.target).$”, std::regex_constants::multiline | std::regex_constants::dotall) |
| Python | re.M | re.S | re.findall(r’^(?!.target).$', text, re.M | re.S) |
總結(jié)
- 匹配“不包含指定字符串”的核心是負向環(huán)視
(?!...),基礎(chǔ)模板為^(?!.*目標字符串).*$; - 讓
.匹配換行符需開啟單行模式:PHP /s、Java Pattern.DOTALL、Golang (?s)、JavaScript /s、C++ dotall、Python re.S; - 多語言按行匹配需開啟多行模式:PHP /m、Java Pattern.MULTILINE、Golang (?m)、JavaScript /m、C++ multiline、Python re.M;
- 排除多個字符串時,疊加多個負向環(huán)視斷言即可,邏輯簡單且易擴展;
- 不同語言的正則語法和標志略有差異,但核心原理相通,掌握一種后可快速遷移到其他語言。
到此這篇關(guān)于正則表達式匹配不包含指定字符串的文本的文章就介紹到這了,更多相關(guān)正則表達式匹配不包含指定字符串內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java正則相關(guān)的Pattern和Matcher類及遇到的坑
這篇文章主要介紹了Java正則相關(guān)的Pattern和Matcher類及遇到的坑,本文給大家提到了Matcher 里面的三個方法,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-09-09
Java用正則對字符串進行處理并判斷是否能轉(zhuǎn)為數(shù)字
這篇文章主要介紹了Java用正則對字符串進行處理并判斷是否能轉(zhuǎn)為數(shù)字的實例代碼,代碼很簡單,需要的朋友可以參考下2018-06-06

