Grep 表达式过滤掉 [alnum][punct][alnum] 形式的行
Grep expression filter out lines of the form [alnum][punct][alnum]
大家好,我的第一个 post 是为了我认为很简单的事情......
我没能找到类似的例子 problem/solution。
我有数千个文本文件,其中包含数千行内容,格式为
<word><space><word><space><number>
示例:
example for 1
useful when 1
for. However 1
,boy wonder 1
,hary-horse wondered 2
在上面的示例中,我想排除第 3 行,因为它包含内部标点符号
我正在尝试使用 GNU grep 2.25,但运气不好
我最初的尝试是(但是这不允许模式内部的“-”):
grep -v [:alnum:]*[:punct:]*[:alnum:]* filename
所以尝试了这个
grep -v [:alnum:]*[:space:]*[!]*["]*[#]*[$]*[%]*[&]*[']*[(]*[)]*[*]*[+]*[,]*[.]*[/]*[:]*[;]*[<]*[=]*[>]*[?]*[@]*[[]*[\]*[]]*[^]*[_]*[`]*[{]*[|]*[}]*[~]*[.]*[:space:]*[:alnum:]* filename
但是我需要考虑空格和 - 因为这些在字符串内部是可以接受的。
我一直在尝试使用 :punct" 集,但现在看到它包含 - 很明显那是行不通的
我目前在 TSQL 中有一个存储过程来处理这些,但是如果可能的话我更愿意在加载之前进行预处理,因为例程每个文件需要几秒钟。
有人能做到类似的事情吗?
您的正则表达式包含一长串有序的可选元素,但这意味着如果出现乱序,它将失败。例如,
[!]*[?]*
将捕获 !?
但不会捕获 ?!
(当然,包含单个字符的字符 class 只等同于该单个字符,因此您不妨说 !*?*
).
您可以改用单个字符 class,其中包含您要捕获的所有符号。一旦您在字母数字字符旁边看到一个,您就完成了,因此您不需要正则表达式匹配整个输入行。
grep -v '[[:alnum:]][][!"#$%&'"'"'()*+,./:;<=>?@\^_`{|}~]' filename
还要注意表达式需要如何用单引号引起来,以便 shell 不会干扰此处的许多元字符。为了使单引号字符串包含文字单引号,我暂时分成双引号字符串;参见 here 的解释(我称之为 "seesaw quoting")。
在一个字符class中,如果class需要包含]
,则需要在枚举列表的开头;为了对称和成语,我也把[
移到了旁边
此外,正如 Jonathan Leffler 所指出的,POSIX 字符 class 名称需要位于字符 class 内;所以要匹配属于 [:alnum:]
命名集的一个字符,你说 [[:alnum:]]
。 (这意味着您可以组合集合,因此 [-[:alnum:].]
涵盖字母数字加上破折号和句点。)
如果您需要将其限制为仅匹配第一个字段,请将 [[:alnum:]]
更改为 ^[[:alnum:]]\+
。
没有意识到 a*b*c*
匹配 任何东西 是一个常见的新手错误。您希望避免编写所有元素都是可选的表达式,因为它会匹配所有可能的字符串。专注于您想要匹配的内容(在您的情况下是一长串标点符号),然后如果确实需要,可以在其周围添加可选的上下文;但是您需要的这些越少,它就会越快 运行,也就越容易看到它的作用。作为一个快速的经验法则,a*bc*
实际上精确地等同于 b
——前导或尾随的可选表达式也可以不指定,因为它们不会影响将要匹配的内容。
从表面上看,您正在寻找 'word space word space number' 架构,假设 'word' 是 'one alphanumeric optionally followed by zero or one occurrences of zero or more alphanumeric or punctuation characters and ending with an alphanumeric',并且 'space' 是 'one or more spaces' 并且'number' 是 'one or more digits'.
根据 grep -E
(又名 egrep
):
grep -E '[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:digit:]]+'
包含:
[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?
检测带有任何标点符号并被字母数字包围的单词,并且:
[[:space:]]+
[[:digit:]]+
查找一个或多个空格或数字。
使用稍微扩展的数据文件,这会产生:
$ cat data
example for 1
useful when 1
for. However 1
,boy wonder 1
,hary-horse wondered 2
O'Reilly Books 23
Coelecanths, Dodos Etc 19
$ grep -E '[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:digit:]]+' data
example for 1
useful when 1
,boy wonder 1
,hary-horse wondered 2
O'Reilly Books 23
Coelecanths, Dodos Etc 19
$
它根据需要删除了 for. However 1
行。
大家好,我的第一个 post 是为了我认为很简单的事情......
我没能找到类似的例子 problem/solution。
我有数千个文本文件,其中包含数千行内容,格式为
<word><space><word><space><number>
示例:
example for 1 useful when 1 for. However 1 ,boy wonder 1 ,hary-horse wondered 2
在上面的示例中,我想排除第 3 行,因为它包含内部标点符号
我正在尝试使用 GNU grep 2.25,但运气不好
我最初的尝试是(但是这不允许模式内部的“-”):
grep -v [:alnum:]*[:punct:]*[:alnum:]* filename
所以尝试了这个
grep -v [:alnum:]*[:space:]*[!]*["]*[#]*[$]*[%]*[&]*[']*[(]*[)]*[*]*[+]*[,]*[.]*[/]*[:]*[;]*[<]*[=]*[>]*[?]*[@]*[[]*[\]*[]]*[^]*[_]*[`]*[{]*[|]*[}]*[~]*[.]*[:space:]*[:alnum:]* filename
但是我需要考虑空格和 - 因为这些在字符串内部是可以接受的。
我一直在尝试使用 :punct" 集,但现在看到它包含 - 很明显那是行不通的
我目前在 TSQL 中有一个存储过程来处理这些,但是如果可能的话我更愿意在加载之前进行预处理,因为例程每个文件需要几秒钟。
有人能做到类似的事情吗?
您的正则表达式包含一长串有序的可选元素,但这意味着如果出现乱序,它将失败。例如,
[!]*[?]*
将捕获 !?
但不会捕获 ?!
(当然,包含单个字符的字符 class 只等同于该单个字符,因此您不妨说 !*?*
).
您可以改用单个字符 class,其中包含您要捕获的所有符号。一旦您在字母数字字符旁边看到一个,您就完成了,因此您不需要正则表达式匹配整个输入行。
grep -v '[[:alnum:]][][!"#$%&'"'"'()*+,./:;<=>?@\^_`{|}~]' filename
还要注意表达式需要如何用单引号引起来,以便 shell 不会干扰此处的许多元字符。为了使单引号字符串包含文字单引号,我暂时分成双引号字符串;参见 here 的解释(我称之为 "seesaw quoting")。
在一个字符class中,如果class需要包含]
,则需要在枚举列表的开头;为了对称和成语,我也把[
移到了旁边
此外,正如 Jonathan Leffler 所指出的,POSIX 字符 class 名称需要位于字符 class 内;所以要匹配属于 [:alnum:]
命名集的一个字符,你说 [[:alnum:]]
。 (这意味着您可以组合集合,因此 [-[:alnum:].]
涵盖字母数字加上破折号和句点。)
如果您需要将其限制为仅匹配第一个字段,请将 [[:alnum:]]
更改为 ^[[:alnum:]]\+
。
没有意识到 a*b*c*
匹配 任何东西 是一个常见的新手错误。您希望避免编写所有元素都是可选的表达式,因为它会匹配所有可能的字符串。专注于您想要匹配的内容(在您的情况下是一长串标点符号),然后如果确实需要,可以在其周围添加可选的上下文;但是您需要的这些越少,它就会越快 运行,也就越容易看到它的作用。作为一个快速的经验法则,a*bc*
实际上精确地等同于 b
——前导或尾随的可选表达式也可以不指定,因为它们不会影响将要匹配的内容。
从表面上看,您正在寻找 'word space word space number' 架构,假设 'word' 是 'one alphanumeric optionally followed by zero or one occurrences of zero or more alphanumeric or punctuation characters and ending with an alphanumeric',并且 'space' 是 'one or more spaces' 并且'number' 是 'one or more digits'.
根据 grep -E
(又名 egrep
):
grep -E '[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:digit:]]+'
包含:
[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?
检测带有任何标点符号并被字母数字包围的单词,并且:
[[:space:]]+
[[:digit:]]+
查找一个或多个空格或数字。
使用稍微扩展的数据文件,这会产生:
$ cat data
example for 1
useful when 1
for. However 1
,boy wonder 1
,hary-horse wondered 2
O'Reilly Books 23
Coelecanths, Dodos Etc 19
$ grep -E '[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:alnum:]]([[:alnum:][:punct:]]*[[:alnum:]])?[[:space:]]+[[:digit:]]+' data
example for 1
useful when 1
,boy wonder 1
,hary-horse wondered 2
O'Reilly Books 23
Coelecanths, Dodos Etc 19
$
它根据需要删除了 for. However 1
行。