Групи захоплення sed не працюють


27

У мене є рядок формату [0-9]+\.[0-9]+\.[0-9]. Мені потрібно витягнути перше, друге та третє числа окремо. Як я розумію, групи захоплення повинні бути на це здатні. Я повинен бути в змозі використати, sed "s/\([0-9]*\)/\1/gщоб отримати перше число, sed "s/\([0-9]*\)/\2/gотримати друге число і sed "s/\([0-9]*\)/\3/gотримати третє число. У кожному випадку я отримую цілий рядок. Чому це відбувається?


6
Групи захоплення охоплюють всю групу ... не окремі елементи в групі. Вам потрібно щось на зразок, 's/\([0-9]\)\([0-9]\)\([0-9]\).*/\1\2\3/'щоб захопити окремі числа.
Мунір

Відповіді:


45

Ми не можемо дати вам повну відповідь без прикладу вашого вкладу, але я можу вам сказати, що ваше розуміння груп захоплення неправильне. Ви не використовуєте їх послідовно, вони посилаються лише на регулярний вираз з лівого боку того ж оператора заміни. Якщо ти захопиш, наприклад, /(foo)(bar)(baz)/тоді, fooбуде \1, barбуде \2і bazбуде \3. Ви не можете цього зробити s/(foo)/\1/; s/(bar)/\2/, тому що у другому s///дзвінку є лише одна захоплена група, тому \2не буде визначено.

Отже, щоб зафіксувати три групи цифр, вам потрібно буде зробити:

sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'

Або, читабельніше:

sed -E 's/([0-9]*)\.([0-9]*)\.([0-9]*)/\1 : \2 : \3/'

1
Яка користь уникнути дужок у першому прикладі?
Джош М.

2
@JoshM. вам потрібно уникнути їх, щоб їх можна було використовувати для зйомки шаблонів. Зазвичай /(foo)/в sed буде відповідати буквальному (символу, а потім fooі тоді буквальному ). Якщо ви хочете зафіксувати групу, вам потрібно або залишити дужки, або скористатися -Eопцією.
terdon

Я майже завжди використовую -rпрапор, тому припускаю, що тому я ще не наткнувся на це.
Джош М.

1
@JoshM. так, -rпрапор це також зробить, але він не є портативним. GNU sed підтримує це, але багато інших - ні. -EЄ більш універсальним.
тердон

9

Приклад:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'
123

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'
456

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'
78

Або все разом:

$ echo "123.456.78" |sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1 : \2 : \3/'
123 : 456 : 78

2

Використовуйте Sed з -r, -regexp-Extended, щоб уникнути всіх уникнутих дужок.

echo "1234.567.89" | sed -r 's/([0-9]+)\.([0-9]+)\.([0-9]+)/\1, \2, \3/' 
1234, 567, 89    #output
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.