Regex 正则表达式

A regular expression (shortened as regex or regexp; also referred to as rational expression) is a sequence of characters that specifies a search pattern in text. Usually such patterns are used by string-searching algorithms for "find" or "find and replace" operations on strings, or for input validation. It is a technique developed in theoretical computer science and formal language theory.

正则表达式(英语:Regular Expression,常简写为regex、regexp或RE),又称正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。

Regular Expression的Regular一般被译为正则正规常规。此处的Regular即是规则规律的意思,Regular Expression即“描述某种规则的表达式”之意。

正则表达式用来做什么:

  1. 判断一个句子中是否有Lizzy, Hello everyone, my name is Li Zhiyan, you can call me Lizy.
  2. 判断一个字符串中是否有数字, Twenty two is 22
  3. 判断一个字符串中有英文字母, 23n20230n;23+&*^&*
  4. 判断一个字符串中是否有John或者Jone, Look! John's AirPods is becoming AirPod.
  5. 判断一个字符串是否是手机号码, 15195812506
  6. 判断一个字符串是否一Leon开头, Leon is from China.
  7. 判断一个字符串是否是邮件地址, [email protected]
  8. 使用非字符串分割字符串,A, B, c, D, E;F|g

正则表达式表达了什么

  1. 断言(Assertions)
    表示一个匹配在某些条件下发生。断言包含先行断言、后行断言和条件表达式。
  2. 字符类(Character Classes)
    区分不同类型的字符,例如区分字母和数字。
  3. 组和范围(Groups and Ranges)
    表示表达式字符的分组和范围。
  4. 量词(Quantifiers)
    表示匹配的字符或表达式的数量。
  5. Unicode 属性转义(Unicode Property Escapes)
    基于 unicode 字符属性区分字符。例如大写和小写字母、数学符号和标点。

在Python中,可以使用re模块和Pattern来做正则:

import re
p = re.compile(pattern, flags=0)
re.search(pattern, string, flags=re.IGNORECASE)
re.match(pattern, string, flags=0)
re.split(pattern, string, maxsplit=0, flags=0)
re.findall(pattern, string, flags=0)

Pattern.search(string[, pos[, endpos]])
Pattern.match(string[, pos[, endpos]])
Pattern.split(string, maxsplit=0)
Pattern.findall(string[, pos[, endpos]])

在JavaScript中,可以使用var re = /pattern/flags;

import re

p1 = re.compile('Lizzy')
s = 'Hello everyone, my name is Li Zhiyan, you can call me Lizzy.'
p1.search(s)

# [\d] = [^\D]
p2 = re.compile('[0-9]') # \d = [0123456789]n 
p2.search('Twenty two is 22')

p3 = re.compile('[a-zA-Z]') # \w (word) = [a-zA-Z0-9_]
p3.search('23n20230n;23+&*^&*')
<re.Match object; span=(2, 3), match='n'>


特殊符号

  1. \d: 匹配一个数字。等价于[0-9]。
  2. \D: 匹配一个非数字字符。等价于1
  3. \w: 匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_]。
  4. \W: 匹配一个非单字字符。等价于 2
  5. \t: 匹配一个水平制表符 (U+0009)。
  6. \v: 匹配一个垂直制表符 (U+000B)。
  7. \f: 匹配一个换页符 (U+000C)。
  8. \n: 匹配一个换行符 (U+000A)。
  9. \r: 匹配一个回车符 (U+000D)。
  10. \s: 匹配一个空白字符,包括空格、制表符、换页符和换行符。等价于[ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]。
  11. \S: 匹配一个非空白字符。等价于 3
  12. .: 匹配除了换行符\n以外的任意一个字符
  13. \u{hhhh} or \u{hhhhh}: 仅当设置了u标志时)匹配一个十六进制数表示的 Unicode 字符。
# 使用|作为选择
p4 = re.compile('John|Jone')
p4.search('Look! John\'s AirPods is becoming AirPod.')

# 匹配次数 {m,n}
p5 = re.compile('^1[0-9]{10}') # '1\d{10}'
# p5.search('15195812506')
p5.match('15195812506')
<re.Match object; span=(0, 11), match='15195812506'>


匹配次数

  1. {m,n} m次到n次(包含)
  2. {m,} 至少m次
  3. {m} m次
  4. ? 0到1次
  5. + 至少1次
  6. * 任意次(0到∞)

指定匹配位置

  1. ^: 匹配字符串的开头
  2. $: 匹配字符串的末尾
  3. \b: 匹配单词(word)的边界
  4. \B: 匹配非单词边界
p6 = re.compile('^Leon')
s6 = 'Leon is from China.'
p6.search(s6)

# [email protected], \[email protected]  @b.com [\w-] a@b._
p7 = re.compile('[\w\.\-\+]+@[\w-]+[\w\-\.]+([a-zA-Z0-9]+)$')
p7.match('[email protected]')

p8 = re.compile('[,;\|]')
p8.split('A, B, c, D, E;F|g')
['A', ' B', ' c', ' D', ' E', 'F', 'g']


总结

转义

如果你需要使用任何特殊字符的字面值(例如,搜索字符''),你必须通过在它前面放一个反斜杠来转义它。 例如,要搜索'a'后跟''后跟'b',你应该使用/a*b/- 反斜杠“转义”字符'*',使其成为文字而非特殊符号。

高级话题

使用插入语

任何正则表达式的插入语都会使这部分匹配的副字符串被记忆。一旦被记忆,这个副字符串就可以被调用于其它用途,如同使用括号的子字符串匹配之中所述。

通过标志进行高级搜索

一般而言,各种语言中实现的正则表达式有可选参数 (flags) 允许全局和不分大小写搜索等。这些参数既可以单独使用也能以任意顺序一起使用, 并且被包含在正则表达式实例(模式)中。

Python中可以使用re.IGNORECASE不分大小写搜索:

import re
p = re.compile(pattern, flags=0)
re.search(pattern, string, flags=re.IGNORECASE)

JavaScript则是:

标志描述
g全局搜索。
i不区分大小写搜索。
m多行搜索。
s允许 . 匹配换行符。
u使用unicode码的模式进行匹配。
y执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始。
let re = /^\w+\.\S+/gi;

用特殊字符检验输入

字符 含义
(x) 像下面的例子展示的那样,它会匹配 'x' 并且记住匹配项。其中括号被称为捕获括号。
模式`/(foo) (bar) \1 \2/`中的 '(foo)' 和 '(bar)' 匹配并记住字符串 "foo bar foo bar" 中前两个单词。模式中的`\1`和`\2`表示第一个和第二个被捕获括号匹配的子字符串,即 foo 和 bar,匹配了原字符串中的后两个单词。注意`\1`、`\2`、...、`\n` 是用在正则表达式的匹配环节,详情可以参阅后文的 `\n` 条目。而在正则表达式的替换环节,则要使用像 `$1`、`$2`、...、`$n` 这样的语法,例如,`'bar foo'.replace(/(...) (...)/, '$2 $1')`。$& 表示整个用于匹配的原字符串。
(?:x) 匹配 'x' 但是不记住匹配项。这种括号叫作非捕获括号,使得你能够定义与正则表达式运算符一起使用的子表达式。
看看这个例子 `/(?:foo){1,2}/`。如果表达式是 `/foo{1,2}/,{1,2}` 将只应用于 'foo' 的最后一个字符 'o'。如果使用非捕获括号,则 `{1,2}` 会应用于整个 'foo' 单词。
x(?=y) 匹配'x'仅仅当'x'后面跟着'y'.这种叫做先行断言。
例如,`/Jack(?=Sprat)/`会匹配到'Jack'仅当它后面跟着'Sprat'。`/Jack(?=Sprat|Frost)/`匹配‘Jack’仅当它后面跟着'Sprat'或者是‘Frost’。但是‘Sprat’和‘Frost’都不是匹配结果的一部分。
(?<=y)x 匹配'x'仅当'x'前面是'y'.这种叫做后行断言。
例如,`/(?<=Jack)Sprat/`会匹配到' Sprat '仅仅当它前面是' Jack '。`/(?<=Jack|Tom)Sprat/`匹配‘ Sprat ’仅仅当它前面是'Jack'或者是‘Tom’。但是‘Jack’和‘Tom’都不是匹配结果的一部分。
x(?!y) 仅仅当'x'后面不跟着'y'时匹配'x',这被称为正向否定查找。
例如,仅仅当这个数字后面没有跟小数点的时候,`/\d+(?!\.)/` 匹配一个数字。正则表达式`/\d+(?!\.)/.exec("3.141")`匹配‘141’而不是‘3.141’

Reference / 参考

  1. Wiki:正则表达式
  2. JavaScript:正则表达式
  3. Python:Regular expression operations
  4. Java:Pattern
  5. .NET:Regular Expression Language - Quick Reference

  1. 0-9
  2. A-Za-z0-9_
  3. \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff

Salesforce Advice

Reduce class level variables data storage

Don't use class level variables to store a large amounts of data.

User SOQL for Loops

Utilize SOQL For Loops to iterate and process data from large queries.

for(Conatct ctt : [Select Id,Name,Account.Name FROM Contact]) {
    // do your work
}

Shorten variables lifetime

Construct methods and loops that allow variables to go out of scope as soon as they are no longer needed.

Other Advice

Using Efficient Algorithms

Being the heart of any code, algorithms can make or break the running of your application. A good space-efficient algorithm can save a lot of your heap memory while simultaneously performing smoothly. Before developing any logic or writing any code snippet, sit, and think through the algorithms to use and choose the one that serves your purpose and makes use of the heap memory efficiently. Try not to split the parts of your algorithms into different functions; rather try to keep them in line when used only within that code.

Built-in Apex libraries

Try to leverage and make use of the inbuilt Apex libraries that Salesforce provides other than writing your custom logic for everything. For example, use the Math class for performing mathematical operations, use JSONGenerator class to create JSON structures, and many more. One line of method calling code is way better than rewriting the logic on your own. This not only saves you time but also the heap memory is managed efficiently.

Avoid using temporary variables

Creating temporary variables is a favorite practice of many developers. We unknowingly create such variables in our code without realizing that we can do without them. These variables take up unnecessary space and add up to the heap memory.

Shorten variable names & declarations

You can spare characters when naming temporary variables like loop counter variables as i instead of myCounter. You should keep meaningful names according to the business.
You can also combine variable declarations like:

Integer i = 0, j = 10;

Shorten Field API Name

We all love to give meaningful names to the custom fields in Salesforce objects. Little do we know that a long API name impacts the code heap size. For example, it is counted in SOQL query size, code that references the field, and each time it is accessed. Maximum length of SOQL statements is 100K.

Remove unnecessary debug statements

Since all the debug statements are counted against the code length, it is necessary to keep a cap on them in order to limit the consumed heap size of the Apex code. It is fine to use them while doing the apex development but should be removed or minimized in the final production version of the code.

Reference

wikipedia:四川话

四川话(四川话拼音:Si4cuan1hua4;国际音标:[sɨ˨˩˧tsʰwan˥˥xwa˨˩˧]),是流行于中国四川省、重庆市(巴蜀地区)及周边省份临近地区的主要汉语言,包括汉语西南官话中的成渝片及灌赤片。
500px-Sichuanese.png

特殊字符供复制拷贝

分类字符用途
数字上标⁰ ¹ ² ³ ⁴ ⁵ ⁶ ⁷ ⁸ ⁹ ⁺ ⁻ ⁼ ⁽ ⁾ ⁿ ′可组运算符号:3⁵,m³, ²/₃
数字下标₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉可组化学符号:O₂,CH₄,H₂S
字母上标大写ᵃ ᵇ ᶜ ᵈ ᵉ ᶠ ᵍ ʰ ⁱ ʲ ᵏ ˡ ᵐ ⁿ ᵒ ᵖ ʳ ˢ ᵗ ᵘ ᵛ ʷ ˣ ʸ ᶻ
字母上标小写ᴬ ᴮ ᴰ ᴱ ᴳ ᴴ ᴵ ᴶ ᵏ ᴸ ᴹ ᴺ ᵖ ᴿ ˢ ᵀ ᵘ ᵛ ᵂ ˣ
数学运算符≤ ≥ ± ∓ × ÷ ∧ ∨ ≃ ≂ ∻ < ≦ ≧ ≨ ≩ ≪ ≫ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≼ ≻ ≺ ∑ ∑ ⨊
其他⊕⊖⊗⊠¬∩∪∝∞ℵℶℷℸℏℇ∀∁∂℮∃∄∅∆∇⊂⊃⊄∈⊋⊆⊇⊈⊉⊅∉∊∋∌∍∧∨ ⨋∕∖∏∐∜∛∦∬∮∯∫∲∰⨔⨖⨚⨙⨘⨛

比如更改root用户密码:

SET PASSWORD FOR 'root'@'localhost' = PASSWORD('mypass');
FLUSH PRIVILEGES;

以上会更改localhost链接的root用户密码,想要更改所有域的链接的root用户密码,使用:

SET PASSWORD FOR 'root'@'%' = PASSWORD('mypass');
FLUSH PRIVILEGES;