精通正则表达式学习记录 第二章

这里讲的一个例子是将Text(文本)转化文HTML的正则表达式的书写过程–书中67页

Text-to-Html转换

我们写一个完成上述任务的小工具(使用Perl语言)
为了将正则表达式运用在整个文本上,而不是一行一行处理,可以使用Perl提供的功能进行转化:

undef $/;		#进入“file-slurp”(文件读取)模式
$text = <>;		#读入命令行中的第一个文件
print $text;

处理特殊字符

将原始文本中的特殊的字符转换为对应的HTML编码,比如'&', '<', '>'等等在HTML中具有特殊意义的字符。需要将他们转换成'&amp', '&lt', '&gt'。简单的转化如下:

$text =~ s/&/&amp;/g;     #保证基本的html字符转换后不会出错
$text =~ s/</&lt;/g;	  
$text =~ s/>/&gt;/g;

分隔段落

使用html tag中表示分段的<p>来标记段落,所以要写出找到段落的正则表达式。下面这个最先想到的写法是:

$text =~ s/^$/<p>/g;

上面的代码把空行作为段落之间的分隔。他可以匹配“行末尾紧随行开头的位置”。但是^$匹配的通常不是逻辑行的开头和结尾,也就是一个逻辑行可能占多行文本。
为此,大多数支持正则表达式的语言提供了“增强的行锚点”匹配模式,在这个模式中,^$会从字符串模式切换到需要的逻辑行模式。在Perl中可以使用/m修饰符来选择此模式:

$text =~ s/^$/<p>/mg;

不过,如果在“空行”中包含空格符或其他空白字符上述正则就不能成功运作。为了处理空白字符,可以使用^。*$,或者^[。\t\r]*$来匹配某些系统在换行符之前的空格符、制表符或者回车符。
另外正则表达式^\s*$也可以处理有空格、空白字符的空行,但是由于\s本身能够匹配换行符,所以整个表达式的意义就不再是“寻找空行及只包括空白字符的行”,而是“寻找空行和只包括空白字符的行的结合”。这可以将连续的空白行进行合并,能够获得更好的体验。所以使用这个好一点。

将E-mail地址转换为超链接形式

识别出email地址,并将其转换成mailto链接。email地址:jfriedl@oreilly.com会被转化为
<a href="mailto:jfredl@oreilly.com">jfriedl@oreilly.com</a>
如何匹配email地址的正则形式可以写成下面这样:

$text =~ s/\b(username regex\@hostname regex)\b/<a href="mailto:$1">$1<\/a>/g;

注意上面的a结尾标签需要对/进行转义。
\b包裹正则的原因是为了排除一些如"jfried@orilly.compiler"的例子。

匹配用户名和主机名

要写正则表达式来匹配,先要清楚这个要匹配的文本的模式,主机名的一些例子如下所示:

regex.info;
www.oreilly.com

它们由点号分隔,以com, edu, info, uk或者其他事先规定的字符序列结尾。根据这个可以先写出一个最简单的匹配email地址的办法:

\w+\@\w+(\.\w+)

\w来匹配用户名,以及主机名的各个部分。不过,实际应用需要考虑的更多才能完成工作。用户名可以包含点号和连字符,所以可以写成:

\w[-.\w]*

这样保证用户名以\w开头后面部分可以包括点号和连字符。
主机名的匹配要复杂一些。有一个简单的雏形如下:

\w+(\.\w+)+

上述正则保证了有点号,但是也可能匹配Artichokee4@1.00这样的字符串。所以还要更细心的考虑。
一个办法是给出末尾部分所有可能出现的序列,跟在\w+(\.\w+)*\.(com|edu|info)之后。
这样就能容许开头的\w部分,然后是可能出现的\.\w部分,最后是我们指定的可能结尾。

实际上\w有些不合适,因为它能匹配ASCII字母和数字,但有些流派的\w能匹配非ASCII字母。所以要改一下得到主机名可能的一种写法如下:

[-a-z0-9]+(\.[a-z0-9]+)*\.(com|edu|info)

正则表达式除了可以用//包裹,还可以使用其他的符号比如{}。下面是综合起来的text转换为HTML方法:

undef $/;				# 进入“文件读取”模式
$text =<>;				# 读入命令行中指定的第一个文件名
$text =~ s/&/&amp;/g;	# 替换HTML基本符号
$text =~ s/</&lt;/g;	# 
$text =~ s/>/&gt;/g;

$text =~ s/^\s*$/<p>/mg;	#划分段落

# 转换为链接形式
$text =~ s{
	\b
	# 把地址保存到$1 ...
	(
		\w[-.\w]*		# username
		\@
		[-a-z0-9]+(\.[a-z0-9]+)*\.(com|edu|info)	#hostname
	)
	\b
}{<a href="mailto:$1">$1</a>}gix;
print $text;	# 最后,显示HTML文本

注意只有用于划分段落的正则表达式才是用/m修饰符。

把http URL替换为链接形式

类似的,先分析URL的模式:

http://hostname/path

其中/path部分是可选的。于是我们得到下面的形式

$text =~ s{
	\b
	#将URL保存到$1中
	(
	  http:// hostname
	  (
		/path
	  )?
	)
}{<a href="$1">$1</a>}gix;

主机名部分的匹配可以使用在email中分析出来的正则表达式。URL中的/path部分可以包含各种字符,比如在先前一章中使用的:

[-a-z0-9_:@&?=+,.!/~*'%$]

它包含了除空白字符,控制字符和<>()之外的大多数ASCII字符。
我们要对&@进行转义:

$text =~ s/{
	\b
	# 将URL保存在$1
	(
		http://[-a-z0-9]+(\.[-a-z0-9]+)*(com|edu|info) \b #hostname
		(
			/ [-a-z0-9_:\@&?=+,.!~*'%\$]*  # path不一定出现
		)?
	)
}{<a href="$1">$1</a>}gix;

path后面没有\b因为URL后面一般都是标段符号,如:
http://www.oreilly.com.catalog/regex3/,如果末尾有\b就不能匹配。
然后,就可以得到完整的程序

undef $/;
$text = <>;

$text =~ s/&/&amp;/g;
$text =~ s/</&lt;/g;
$text =~ s/>/&gt;/g;

$text =~ s/^\s*$/<p>/mg;

#将email转换为链接形式
$text =~ s{
	\b
	(
		\w[-.\w]*
		\@
		[-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info)
		
	)
	\b
}{<a href="$1">$1</a>}gix;

#将http URL转为链接
$text =~ s{
	\b
	(
		http:// [-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info) \b
		(
			/[-a-z0-9:_\@&?=+,.!/~*'%\$]*
		)?
	)
}{<a href="$1">$1</a>}gix;
print $text;

回到单词重复的问题

代码如下

$/ = ".\n";
while (<>) {
	next if !s/\b([a-z]+)((?:\s|<[^>]+>)+)(\1\b)/\e[7m$1\e[m$2\e[7m$3\e[m/ig;
	s/^(?:[^\e]*\n)+//mg;	#删除所有的未标记的行
	s/^/$ARGV: /mg;			#在行首增加文件名
}

这里要做一些解释才能看懂上面的代码:

首先最外面的while循环会便利所有的文本行,
接下来的next if如果不为true,也就是第一个表达式没匹配成功,就会进行下一次循环。
\e[7m是高亮显示的开头,\e[m是高亮显示的结尾。也就是被这两个东西框柱的部分会高亮显示
接下来的一个匹配会将没有出现重复单词的行移除
最后一行在每一行的前面加上文件名

用java实现重复单词问题

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

public class TwoWord
{
	public static void main(String [] args)
	{
		Pattern regex1 = Pattern.compile(
			"\\b([a-z]+)((?:\\s|\\<[^>]+\\>)+)(\\1\\b)",
			Pattern.CASE_INSENSITIVE);
		String replace1 = "\033[7m$1\033[m$2\033[7m$3\033[7m";
		Pattern regex2 = Pattern.compile("^(?:[^\\e]*\\n)+",Pattern.MULTILINE);
		Pattern regex3 = Pattern.compile("^([^\\n]+)",Pattern.MULTILINE);
		//对于命令行的每个参数进行如下处理
		for (int i = 0; i < args.length; i++)
		{
			try {
				BufferedReader in = new BufferedReader(new FileReader(args[i]));
				String text;
			//For each paragraph of each file...
			while((text = getPara(in)) != null)
			{
				//应用3条替换规则
				text = regex1.matcher(text).replaceAll(replace1);
				text = regex2.matcher(text).replaceAll("");
				text = regex3.matcher(text).replaceAll(args[i] + ": $1");
//显示结果
				System.out.print(text);
			} 
			}catch(IOException e) {
				System.err.println("can't read ["+args[i]+"]: " + e.getMessage());
				
			}
		}
	}
	//用于读入“一段”文本的子程序
	static String getPara(BufferedReader in) throws java.io.IOException
	{
		StringBuffer buf = new StringBuffer();
		String line;
		while ((line = in.readLine()) != null &&
			(buf.length() == 0 || line.length() !=0))
			{
				buf.append(line + "\n");
			}
		return buf.length() == 0 ? null : buf.toString();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
正则表达式是一种用来描述和匹配字符串模式的工具。通过了解和掌握正则表达式,可以更高效地处理和操作文本数据。 精通正则表达式PDF是一本详细介绍和讲解正则表达式的电子书,其内容涵盖了正则表达式的基础知识和高级应用技巧。 首先,这本PDF将从基础知识开始介绍正则表达式的语法和常用的元字符,包括字符类、限定符、分组和捕获等。通过学习这些基础知识,读者可以了解如何构建简单的正则表达式来匹配指定的字符串模式。 其次,这本PDF还介绍了正则表达式的高级用法,例如反向引用、零宽断言和嵌入代码等。这些高级技巧可以帮助读者更准确地定位和捕获特定的字符串内容。 除了语法和用法介绍,这本PDF还提供了大量的实例和案例分析,通过具体的示例来演示如何使用正则表达式解决常见的文本处理问题。这些实例覆盖了从简单的字符串匹配到更复杂的文本提取和替换等不同应用场景。 此外,这本PDF还介绍了一些常用的正则表达式工具和库,如Python的re模块和JavaScript的RegExp对象等。这些工具和库提供了更便捷和高效的正则表达式操作方式,读者可以根据自己的需要选择和使用。 总结来说,精通正则表达式PDF是一本系统和全面介绍正则表达式的电子书,通过学习这本书,读者可以掌握正则表达式的基础知识和高级应用技巧,并且能够运用正则表达式解决实际的文本处理问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值