开发者

regexp: reversing similar elements in a string

I am using my texteditor (e-texteditor)'s regular expression to try to reverse some elements in a line of code. So here's what I have:

  [[Date.today, "Today (#{Date.today})"], [Date.tomorrow, "Tomorrow (#{Date.tomorrow})"], [Date.today+3, "In 3 Days (#{Date.today+3})"], [this_weekend, "This Weekend (#{this_weekend})"]]开发者_如何转开发

And I actually wanted it the reverse of it:

  [[this_weekend, "This Weekend (#{this_weekend})"], [Date.today+3, "In 3 Days (#{Date.today+3})"], [Date.tomorrow, "Tomorrow (#{Date.tomorrow})"], [Date.today, "Today (#{Date.today})"]]

By the way, the code is in Ruby in case you're wondering. To visualize better:

Have: [A, B, C, D] Want: [D, C, B, A]

So far, I am doing the dumb thing (or at least I think so) by searching for

 (\[[^[].+?\]),\s(\[[^[].+?\]),\s(\[[^[].+?\]),\s(\[[^[].+?\]) 

so it's like search for (A),\s(B),\s(C),\s(D)

And then replace it with

  $4, $3, $2, $1

While that works, but it's not very nice isn't it, what if I have more than 4 elements. That's a lot of typing up still. How will you approach it?

Here is the regex 'engine/syntax' that e-texteditor supports

regexp: reversing similar elements in a string

Thank you!


well i post an awk oneliner to solve your problem. if you have to stick to your editor, just forget it.

awk -F'\\[\\[|\\]\\]|\\], *\\[' '{for (i=NF;i>=1;i--) {s=s&&$i?s",":s;s=($i)?s"["$i"]":s"";} s="["s"]";print s}'    yourFile

testing:

this is the string we want to test:

kent$  echo {1..10}|sed -r 's/([0-9]+)/[\1],/g;s/^/[/;s/,$/]/'  

[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]

now push it to my awk script:

kent$  echo {1..10}|sed -r 's/([0-9]+)/[\1],/g;s/^/[/;s/,$/]/'|awk -F'\\[\\[|\\]\\]|\\], *\\[' '{for (i=NF;i>=1;i--) {s=s&&$i?s",":s;s=($i)?s"["$i"]":s"";} s="["s"]";print s}'   

[[10],[9],[8],[7],[6],[5],[4],[3],[2],[1]]

with the given example from you:

kent$  echo '[[Date.today, "Today (#{Date.today})"], [Date.tomorrow, "Tomorrow (#{Date.tomorrow})"], [Date.today+3, "In 3 Days (#{Date.today+3})"], [this_weekend, "This Weekend (#{this_weekend})"]]'|awk -F'\\[\\[|\\]\\]|\\], *\\[' '{for (i=NF;i>=1;i--) {s=s&&$i?s",":s;s=($i)?s"["$i"]":s"";} s="["s"]";print s}'    

[[this_weekend, "This Weekend (#{this_weekend})"],[Date.today+3, "In 3 Days (#{Date.today+3})"],[Date.tomorrow, "Tomorrow (#{Date.tomorrow})"],[Date.today, "Today (#{Date.today})"]]


This (\[[^[].+?\]), could be a problamatic subexpression.
It works in this case because the sample data you provide is
well formed. In ill-formed context, it could overflow to the next ],
if not preceded by a [, even though .+? is non greedy.

It might be better as this (\[[^\[\]]+\]).

To your question, I think that only .NET has variable amount of
capture buffers (its Capture Collection) and even then I'm not sure how its variability could be used on the replacement side.
Example: \[(?:(\[[^\[\]]+\])(?:,\s*|(?=\])))+\] should make a variable collection that you may be able to programatically reverse on the replacement side. I've never done this so not too sure.

Otherwise, it involves a couple of seperate intermediate steps
outside of a regex.

In Perl, it'd be like use global search and replace, where the
replacement side is a callback function that gets passed each individual record.

s/(\[(?:\[[^\[\]]+\](?:,\s*|(?=\])))+\])/ func($1) /eg;`

Then in the callback, parse the individual elements from the record passed, then
rebuild the string in reverse order, which then gets passed back to the original
regex to be used as the replacement for that record.

Perl code:

use strict;
use warnings;

my $samp = '[[Date.today, "Today (#{Date.today})"], [Date.tomorrow, "Tomorrow (#{Date.tomorrow})"], [Date.today+3, "In 3 Days (#{Date.today+3})"], [this_weekend, "This Weekend (#{this_weekend})"]]';

$samp =~ s/(\[(?:\[[^\[\]]+\](?:,\s*|(?=\])))+\])/ func($1) /eg;

print "\n$samp\n";


sub func
{
   my $rec = shift;
   my @elements = $rec =~ /(\[[^\[\]]+\])/g;
   return '['. join( ', ', reverse @elements ) . ']';
}

Output:

[[this_weekend, "This Weekend (#{this_weekend})"], [Date.today+3, "In 3 Days (#{Date.today+3})"], [Date.tomorrow, "Tomorrow (#{Date.tomorrow})"], [Date.today, "Today (#{Date.today})"]]
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜