4

我正在尝试使用 sed 来切换句子中第一个和最后一个单词的顺序,因为在这种情况下,我认为我不明白“贪婪”正则表达式的含义。仅仅因为三个字的一句话,我就惨败了。

$ echo hello world mike | sed 's/\([a-z]*\).* \([a-z]*\).*/\2 \1/'
mike hello

为什么输出不是“world hello mike”?一些可能有用的额外信息。

  1. \1 \2 是第一个和第二个正则表达式匹配

  2. 我在这里学习教程

我的最终目标是切换句子中第一个和最后一个单词的顺序,而不管其中有多少单词。

4

7 回答 7

7

您没有将该hello部分包含为您的捕获组之一,因此它不会得到输出。尝试:

$ sed -E 's/([a-z]+) (.+) ([a-z]+)/\3 \2 \1/' <<< "hello world mike"
mike world hello
$ sed -E 's/([a-z]+) (.+) ([a-z]+)/\3 \2 \1/' <<< "hello world foo bar baz mike"
mike world foo bar baz hello

(注意:我还删除了您对 echo 的无用使用。)

您也可以替换[a-z]with[[:alpha:]]来处理大写字母:

$ sed -E 's/([[:alpha:]]+) (.+) ([[:alpha:]]+)/\3 \2 \1/' <<< "Hello world Mike"
Mike world Hello
于 2013-10-18T22:41:33.673 回答
3

另一个awk版本

echo hello world mike | awk '{s=$1;$1=$NF;$NF=s}1'
mike world hello

只需交换最后一个文件和第一个文件就可以了。

于 2013-10-18T22:46:23.657 回答
2
$ echo "hello world mike" | sed -r 's/([^ ]+)(.* )([^ ]+)/\3\2\1/'
mike world hello
$ echo "this is a simple sentence" | sed -r 's/([^ ]+)(.+ )([^ ]+)/\3\2\1/'
sentence is a simple this

或在仅支持 BRE 而不是 ERE 的旧 sed 中:

$ echo "hello world mike" | sed 's/\([^ ]*\)\(.* \)\([^ ]*\)/\3\2\1/'
mike world hello
$ echo "this is a simple sentence" | sed 's/\([^ ]*\)\(.* \)\([^ ]*\)/\3\2\1/'
sentence is a simple this
于 2013-10-19T02:47:52.767 回答
1

您要求交换行中的第一个和最后一个单词-因此您需要确保捕获那些(而不是第一个和第二个单词,就像上述许多答案一样)。

echo "hello cruel and unkind world" | sed 's/^\([^ ]*\) \(.*\) \([^ ]*\)$/\3 \2 \1/'

将导致

world cruel and unkind hello

下面是它的工作原理:

^\([^ ]*\)  - starting at the beginning of the line (^), find as many non-space characters as you can (stops at first space)
              note - depending on the flavor of sed you use, there are special symbols to map "a non whitespace, e.g. \S
            - the next space is matched but not captured
\(.*\)      - capture "everything" after this, until...
 \([^ ]*\)$ - a space followed by all non-space characters followed by the end of string

然后,当您以相反的顺序输出三个捕获组时,中间有一个空格,您会得到您所要求的内容。

于 2013-10-18T22:59:22.013 回答
1

使用

$ echo 'hello world mike' | awk '{v1=$1;v2=$NF;$1=$NF="";print v2, $0, v1}'
mike  world  hello
于 2013-10-18T22:43:02.507 回答
1

带有单词边界的 sed 命令:

sed 's/\([A-Za-z]\+\)\(.\+\)\b\([A-Za-z]\+\)/\3\2\1/'

或在扩展模式下:

sed -r 's/([A-Za-z]+)(.+)\b([A-Za-z]+)/\3\2\1/'
于 2013-10-18T23:08:12.457 回答
0

我会使用另一种方法,比如split()更强大的语言,但是对于你必须将所有内容分组在两个边缘词之间:

echo hello world mike | sed 's/\([a-z]*\)\(.*\) \([a-z]*\).*/\3\2 \1/'

它产生:

mike world hello
于 2013-10-18T22:41:20.683 回答