grep命令显示以相同字符开头和结尾的所有行


Answers:


14

POSIXly:

pattern='\(.\).*\1
.'
grep -x -- "$pattern" file

如果行以无效的字节字符开始或结束行将不起作用,如果要覆盖这种情况,可以添加LC_ALL=C,尽管仅LC_ALL=C适用于单字节字符数据。


perl6 如果您将其放在包装盒中,它似乎是最好的工具:

$ printf '\ue7\u301 blah \u107\u327\n121\n1\n123\n' |
  perl6 -ne '.say if m/^(.).*$0$/ || /^.$/'
ḉ blah ḉ
121
1

虽然它仍然会使无效字符窒息。


请注意,这perl6将通过将其变成NFC表格来更改您的文本:

$ printf '\u0044\u0323\u0307\n' |
  perl6 -pe ''                  |
  perl -CI -ne 'printf "U+%04x\n", ord for split //'
U+1e0c
U+0307
U+000a

$ printf '\u0044\u0323\u0307\n' |
  perl -pe ''                   |
  perl -CI -ne 'printf "U+%04x\n", ord for split //'
U+0044
U+0323
U+0307
U+000a

在内部,perl6NFG形式(代表Normalization Form Grapheme)存储字符串,这是perl6一种可以正确处理未组合字素的发明方式:

$ printf '\u0044\u0323\u0307\n' | perl6 -ne '.chars.say'
1
$ printf '\u0044\u0323\u0307\n' | perl6 -ne '.codes.say'
2

2
Perl对Unicode文本的处理简直就是模范,以至于Perl中的许多“简单”任务实际上是不可能使用其他工具来实现的,至少具有相同的正确性。
Dietrich Epp

1
应当注意,perl6尽管如此会改变文本(将其转换为NFC(归一化形式为“ composed”(归一化)形式))。
斯特凡Chazelas

@StéphaneChazelas:是的,很公平。还要注意,in中的字符串以(for )形式perl6存储,这是正确处理未组合字素的一种方式。NFGGGraphemeperl6
cuonglm

10

不是grep而是awk:

awk -F "" 'NF && $1 == $NF'

处理以下特殊情况:

  • 它不打印空行
  • 它总是打印1个字符的行

空的FS会将记录拆分为gawkmawk和中的每个字段一个字符busybox awk(字节,不是后两个字符),但这不是标准的,并且在awkA,W和K的原始字段派生的实现中不起作用在BSD和Universe商业上。更便于携带,但需要输入:

awk '/./ && substr($0,1,1) == substr($0,length)'

1
请注意,FS由于空字符串不是标准的,因此在某些awk实现中将不起作用。
cuonglm '16

2
避免分裂并且完全可移植的替代方法(即使对于最大的awk 'length&&substr($0,1,1)==substr($0,length)'length$0{print $0}
Solaris'old'awk

@ dave_thompson_085:谢谢,我只是使用您的默认操作提示来获得最短的命令。
rudimeier

Firne。一项小更正;我的Solaris旧awk测试错误(我不小心打开了xpg4),但是这种方法确实有效,nawk几乎一样糟糕:-)
dave_thompson_085

8
grep -xe '\(.\).*\1' -e .

例:

$ printf '%s\n' il y était cet été  | grep -xe '\(.\).*\1' -e .
y
été

-x用于完全匹配(整行匹配)。\1是对中捕获的字符的后向引用\(.\)。我们添加a -e .来照顾包含一个字符的行的特殊情况。

假定输入内容在当前语言环境中包含有效文本。

匹配是在字符上,而不是字节上(不是UTF-8中的é是两个字节0xc3 0xa9),也不是graphem簇(如果这些é以其分解形式写成,e然后是U + 0301,则不起作用)例如结合重音符号)。

要使用grep支持-PPCRE的石墨烯簇进行工作:

$ printf 'e\u0301te\u0301\n' | grep -xPe '(\X).*\1|\X'
été

假定两个簇的分解是相同的,例如a 表示为c U+0301 U+0327将与a c U+0327 U+0301ćU+0107U+0327çU+00E7U+0301或ḉ(U+1E09)表示的不匹配。为此,您需要对标准化表格进行检查:

$ printf '\ue7\u301 blah \u107\u327\n' |
  perl -MUnicode::Normalize -C -ne '
    print if /^\X$/ || NFC($_) =~ /^(\X).*\1$/'
ḉ blah ḉ

1
如果您有perl6perl6 -ne '.say if m/^(.).*$0$/ || /^.$/'则应为您完成所有工作。
cuonglm '16

1

快速python2替代:

python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rstrip("\n").endswith(l[0])]' < input.txt

例:

$ python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rstrip("\n").endswith(l[0])]' < input.txt  | cat -A 
nathan$
 ookie $
a line a$

如果行包含尾部或前导空格,则失败,例如`121`。
cuonglm

@cuonglm是的。但是,尾随或前导空格是必须的吗?这完成了所要求的工作-检查开头和结尾字符是否相同。空格仍然是ascii字符,不是吗?
Sergiy Kolodyazhnyy

@cuonglm顺便说一句,您的也未能通过领先和尾随的空间:)
Sergiy Kolodyazhnyy

您的代码删除了开头和结尾的空格,因此它更改了输入行。此外,它还会为空行提供错误。
rudimeier

@Serg:怎么样?我的答案只是grepping,它不会修改输入。
cuonglm
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.