Regex to grab the first and last digit that are equal to each other with the grep function

Viewed 370

I am trying to find words that are sandwiched between the same digit in a digit soup. They can be interrupted by digits in other places, but they have to start and end with the same digit. For example:

936694753355715720418156005497888680833462758860829*9ang0io752901403085mat93a9*535

angiomata is sandwiched between two 9s.

936694753355715720418156005497888680833462758860829*9ang0io752901403085mat93a7*535

In the case above it would not be correct because it begins with a 9 but ends with a 7.

It is a .txt file and doesn't contain any space. Every line has the same length and only include lower case letters and digits.I got the letters and numbers between the first and last number but dont know how to take the first and last number that are equal to each other. Thanks for everything in advance.

what I got so far:

$ egrep "[[:digit:]]{1}[a-z]+(.*)[a-z][[:digit:]]{1}" .txt

A few lines from the file: (9th line has the thing that I am looking for - 1ac31069383748462343642622383007520ou280685412598707stical1 - 1acoustical1)

8659143296aconite931031567290592196372720165714862606068549452875678894011583394 429537968991065280440972955773783975aconite405304426503915937177910674938356s995 165730080656179172282158326723459395151887a197343544312497429322conitic971943257 242700348160683825750220278124532230615414861aconi0423t2209041629um7534201414279 8095795129421424035773aconit51122048059352421754855393594um083s57745637407177073 203520740229811376acor4730n05675830009456231936341628077162200687753246324478764 0047610666820884722216474722512324028387365649588049630aco5307rns847715766988588 568901339322354170088854729578680996027154709227496061907093046a199546373coustic 293915167531ac31069383748462343642622383007520ou280685412598707stical13002190096 83982473352438654261757963864323333acou021534520556605043806stical2223ly16922171 02309730655acousti3490661184937075557973850179cia014890505513865828185722n085724 26480962052acousti87311144532313023833020698187076874569358847788485c8205ians518 24711482467426173614aco00496247639921262483584020ustic92007815150348941694311s0 8

2 Answers

Allow only digits from line start until the first [a-z]. I would use grep -oP with something like

^\d*\K(\d)[a-z](?>\d*[a-z]+)*\1
  • at ^ line start \d* any amount of digits and \K resets beginning of the match
  • capture one (\d) before the first [a-z] to group 1
  • followed by (?>\d*[a-z]+)* any amount of atomic group until captured \1 is met

See this demo at regex101

This is doing what you want:

grep -oP '^\d*\K(\d)[a-z]\w+[a-z]\1' file.txt

Output: (from your example)

1ac31069383748462343642622383007520ou280685412598707stical1

Options:

. -o, --only-matching Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line. . -P, --perl-regexp Interpret the pattern as a Perl-compatible regular expression (PCRE). This is highly experimental and grep -P may warn of unimplemented features.

Regex:

^           # beginning of line
  \d*       # 0 or more digits
  \K        # forget all we have seen until this position
  (\d)      # group 1, 1 digit
  [a-z]     # a letter
  \w+       # 1 or more word character, you may use [a-z0-9]+
  [a-z]     # a letter
  \1        # same digit as in group 1

Or a Perl one-liner:

$perl -ane 'if(s/^\d*\K(\d)[a-z]\w+[a-z]\1/$&/){s/\d+//g;print "line: $.: $_"}' file.txt
line: 9: acoustical
Related