1. Главная страница » Perl замена в строке

Perl замена в строке

Автор: | 16.12.2019

До сих пор вы использовали операторы, проверяющие на соответствие образцу. Оказывается, Perl поддерживает два других регулярных выражения, которые мо­дифицируют проверяемую строковую переменную. В записанной дальше инструкции Perl замещает часть строки, которая соответствует образцу, на заданную строку:

Например, следующая инструкция заменит слово « colour » на « color »:

Небольшая модификация позволяет заменить все слова « colour » на « color »:

В данном случае g в конце выражения указывает языку Perl на необходимость глобальной подстановки.

Используя суффикс i , можно задать выполнение поиска с учётом регистра.

В противоположность простой проверке на соответствие образцу, следующее вы­ражение осуществляет также и замену:

Например, замена всех символов нижнего регистра теми же символами верхнею регистра может быть осуществлена таким образом:

tr / a — z / A — Z /; # меняет регистр, с нижнего на верхний

Примеры

  1. Заменить множественные пробелы и нетекстовые символы на одиночные пробелы:

$text = "Here is the text."
$text =

tr[00-40177377][40]s;
print $text;
Here is the text.

Сократить удвоенные, утроенные и т.д. буквы:

$text = "Here is the texxxxxxt.";
$text =

tr/a-zA-Z/s;
print $text;
Here is the text.

Пересчитать количество небуквенных символов:

Обнулить восьмой бит символов, удалить нетекстовые символы:

Заменить нетекстовые и 8-битные символы на одиночный пробел:

Поиск отдельных слов

Чтобы выделить слово, можно использовать метасимвол S соответствующий символам, отличным от "пробельных":

$text = "Now is the time.";
$text =- /(S+)/;
print ;
Now

Однако метасимвол S соответствует также и символам, обычно не используемым для идентификаторов. Чтобы отобрать слова, составленные из латинских букв, цифр и символов подчеркивания, нужно использовать метасимвол w :

$text = "Now is the time.";
$text =

Если требуется включить в поиск только латинские буквы, надо использовать класс символов:

$text = "Now is the time.";
$text =

Более безопасный метод состоит в том, чтобы включить в шаблон мнимые символы границы слова:

$text = "How is the time.";
$text=

Привязка к началу строки

Началу строки соответствует метасимвол (мнимый символ) ^ . Чтобы шаблон к началу строки, надо задать этот символ в начале регулярного выражения. Например, вот так можно проверить, что текст не начинается с точки:

m/^./) <
print "Shouldn’t start a sentence with a period!
";
>
Shouldn’t start a sentence with a period!

Чтобы точка, указанная в шаблоне, не интерпретировалась как метасимвол перед ней пришлось поставить обратную косую черту.

Привязка к концу строки

Чтобы привязать шаблон к концу строки, используется метасимвол (мнимый символ) $ . В нашем примере мы используем привязку шаблона к началу и к концу строки, чтобы убедиться, что пользователь ввел только слово "exit":

Для проверки того, действительно ли пользователь ввел число, можно использо-вать метасимволы d и D . Метасимвол D соответствует любому символу, кроме цифр. Например, следующий код проверяет, действительно ли введенный текст представляет собой целое значение без знака и паразитных пробелов:

$test = "Hello!";
if($text =

/D/) <
print "It is not a number.
";
>
It is not a number.

To же самое можно проделать, использовав метасимвол d:

/^d+$/) <
print "It is a number.
";
>
It is a number.

Вы можете потребовать, чтобы число соответствовало привычному формату. То есть число может содержать десятичную точку, перед которой стоит по краййей мере одна цифра и, возможно, какие-то цифры после нее:

$text= "3,1415926";
if($text =

/^(d+.d*|d+)$/) <
print "It is a number.
";
>
It is a number.

Кроме того, при проверке можно учитывать тот факт, что перед числом может стоять как плюс, так и минус (или пустое место):

$text = "-2.7182";
if ($text =

Поскольку плюс является метасимволом, его надо защищать обратной косой чертой. Однако внутри квадратных скобок, то есть класса символов, он не может быть квантификаторам. Знак "минус" внутри класса символов обычно играет роль оператора диапазона и поэтому должен защищаться обратной косой чертой. Однако в начале или в конце шаблона он никак не может обозначать диапазон, и поэтому обратная косая черта необязательна. Наконец, более строгая проверка, требует, чтобы знак, если он присутствует, был только один:

Читайте также:  Pfc блок питания что это

$text = "+0.142857142857142857";
if ($text =

/^(+|-|)d+(.d*)$/) <
print "It is a number.
";
>
It is a number.

Альтернативные шаблоны, если они присутствуют, проверяются слева направо. Перебор вариантов обрывается, как только найдено соответствие между текстом и шаблоном. Поэтому, например, порядок альтернатив в шаблоне (.d*|) мог бы стать критичным, если бы не привязка к концу строки. Наконец, вот как можно произвести проверку того, что текст является шестна-дцатеричным числом без знака и остальных атрибутов:

$text = "1AO";
unless (ftext =

m/^[a-fA-Fd]+$/) <
print "It is not a hex number,
";
>

Проверка идентификаторов

С помощью метасимвола w можно проверить, состоит ли текст только из букв, цифр и символов подчеркивания (это те символы, которые perl называет словесными (word characters)):

/^w+$/) <
print "Only word characters found.
";
>
Only word characters found.

Однако, если вы хотите убедиться, что текст содержит латинские буквы и несодержит цифр или символов подчеркивания, придется использовать другой шаблон:

Наконец, для проверки, что текст является идентификатором, то есть начинаетcя с буквы и содержит буквы, цифры и символы подчеркивания, можно испольpовать команду:

$text = "X125c";
if($text=

/^[A-Za-z]w+$/) <
print "This is identifier.
";
>
This is identifier.

Как найти множественные совпадения

Для поиска нескольких вхождений шаблона можно использовать модификатор g . Следующий пример, который мы уже видели ранее, использует команду m/. / с модификатором g для поиска всех входжений буквы x в тексте:

$text="Here is texxxxxt";
while($text=

m/x/g) <
print "Found another x.
";
>
Found another x.
Found another x.
Found another x.
Found another x.
Found another x.

Модификатор g делает поиск глобальным. В данном (скалярном) контексте perl помнит, где он остановился в строке при предыдущем поиске. Следующий поиск продолжается с отложенной точки. Без модификатора g команда m/. / будет упорно находить первое вхождение буквы х , и цикл будет продолжаться бесконечно.

В отличие от команды m/. / команда s/. /. / с модификатором g выполняет глобальную замену за один раз, работая так, будто внутри нее уже имеется встроенный цикл поиска, подобный приведенному выше. Следующий пример за один раз заменяет все вхождения х на z :

$text = "Here is texxxxxt.";
$text =

s/x/z/g;
print $text;
Here is tezzzzzt.

Без модификатора g команда s/. /. / заменит только первую букву х . Команда s/. /. / возвращает в качестве значения число сделанных подстановок, что может оказаться полезным:

$text= "Here is texxxxxt.";
print (text =

Поиск нечувствительных к регистру совпадений

Вы можете использовать модификатор i , чтобы сделать поиск нечувствительным к разнице между заглавными и строчными буквами. В следующем примере про-грамма повторяет на экране введенный пользователем текст до тех пор, пока не будет введено Q , или q (сокращение для QUIT или quit), после чего программа прекращает работу:

Выделение подстроки

Чтобы получить найденную подстроку текста, можно использовать круглые скобки в теле шаблона. Если это более удобно, можно также использовать встроенную функцию substr. В следующем примере мы вырезаем из текстовой строки нужный нам тип изделия:

$record = "Product number:12345
Product type: printer
Product price: 5";
if($record=

/Product type:s*([a-z]+)/i) <
print "The product’s type Is^.
";
>
product’s type is printer.

Вызов функций и вычисление выражений при подстановке текста

Используя для команды s/. /. / модификатор е , вы тем самым показываете, что правый операнд (то есть подставляемый текст) — это то выражение perl, которое надо вычислить. Например, с помощью встроенной функции perl uc (uppercase) можно заменить все строчные буквы слов строки на заглавные:

$text = "Now is the time.";
$text=

s/(w+)/uc()/ge;
print $text;
NOW IS THE TIME.

Вместо функции uc($l) можно поместить произвольный код, включая вызовы программ.

Поиск n-го совпадения

С помощью модификатора g перебираются все вхождения заданного шаблона. Но то делать, если нужна вполне определенная точка совпадения с шаблоном, например, вторая или третья? Оператор цикла while в сочетании с круглыми cкобками, выделяющими нужный образец, поможет вам:

$text = "Name:Anne Nanie:Burkart Name:Glaire Name: Dan";
while ($text =

/Name: s*(w+)/g) <
++$match;
print "Match number $match is .
";
>

Match number 1 is Anne
Match number 2 is Burkart
Match number 3 is Claire
Match number 4 is Dan

Читайте также:  O5wap ru зона обмена

Этот пример можно переписать, используя цикл for:

$text = "Name:Anne Name:Burkart Name:Ciaire Name:Dan";
for ($match = 0;
$text =

/Name:s*(w+)/g;
print "Match number $ <match>is .
")
<>
Match nuwber 1 Is Anne
Match number 2 is Burkart
Match number 3 is Claire
Match number 4 is Dan

Если же вам требуется определить нужное совпадение не по номеру, а по содержанию (например, по первой букве имени пользователя), то вместо счетчика $match можно анализировать содержимое переменной , обновляемой при каждом найденном совпадении. Когда требуется не найти, а заменить второе или третье вхождение текста, можно применить ту же схему, использовав в качестве тела цикла выражение perl, вызываемое для вычисления заменяющей строки:

$text = "Name:Anne Name:Burkart Name:Claire Name:Dan";
$match =0;
$text =

s/(Name:s*(w+))/ # начинается код perl
if (++$match == 2) < # увеличить счетчик
"Name:John ()" # вернуть новое значение
> else < ># оставить старое значение
/gex;
print $text;
Name:Anne Name:John (Burkart) Name:ClaireName:Dan

В процессе глобального поиска при каждом найденном совпадении вычисляется выражение, указанное в качестве второго операнда. При его вычислении увеличивается значение счетчика, и в зависимости от него в качестве замены подставляется либо старое значение текста, либо новое. Модификатор х позволяет добавить в поле шаблона комментарии, делая код более прозрачным. Обратите внимание, что нам пришлось заключить весь шаблон в круглые скобки, чтобы получить значение найденного текста и подставить его на прежнее место полностью.

Как ограничить "жадность" квантификаторов

По умолчанию квантификаторы ведут себя как "жадные" объекты. Начиная с текущей позиции поиска, они захватывают самую длинную строку, которой может соответствовать регулярное выражение, стоящее перед квантификатором. Алгоритм перебора с возвратами, используемый perl, способен ограничивать аппетит квантификаторов, возвращаясь назад и уменьшая длину захваченной строки, если не удалось найти соответствия между текстом и шаблоном. Однако этот механизм не всегда работает так, как хотелось бы. Рассмотрим следующий пример. Мы хотим заменить текст "That is" текстом "That’s". Однако в силу "жадности" квантификатора регулярное выражение " .*is " сопоставляется фрагменту текста от начала строки и до последнего найденного "is":

$text = "That is some text, isn’t it?";
$text =

s/.*is/That’s/;
print $texts;
That’sn’t it?

Чтобы сделать квантификаторы не столь жадными, а именно заставить их захватывать минимальную строку, с которой сопоставимо регулярное выражение, после квантификатора нужно поставить вопросительный знак. Тем самым квантификаторы принимают следующий вид:

  • *? — ноль или несколько совпадений,
  • +? — одно или несколько совпадений,
  • ?? — ноль совпадений или одно совпадение,
  • ? — ровно n совпадений,
  • ? — по крайней мере n совпадений,
  • ? — совпадений по крайней мере n , но не более, чем m.

Оратите внимание, что смыслквантификатора от этого не меняется; меняется только поведение алгоритма поиска. Если в процессе сопоставления шаблона и текста прототип определяется однозначно, то алгоритм поиска с возвратами увеличит "жадность" такого квантификатора точно так же, как он ограничивает аппетит собрата. Однако если выбор неоднозначен, то результат поиска будет другим:

$text = "That is some text, isn’t it?";
$text =

s/.*?is/That’s/;
print $texts;
That’s some text, isn’t it?

Как удалить ведущие и завершающие пробелы

Чтобы отсечь от строки начальные "пробельные символы", можно использовать, следующую команду:

$text = " Now is the time.";
$text =

s/^s+//;
print $texts;
Now is the time.

Чтобы отсечь "хвостовые" пробелы, годится команда:

$text = "Now is the time. ";
$text =

s/s+$//;
print $texts;
Now is the time.

Чтобы отсечь и начальные, и хвостовые пробелы лучше вызвать последователно эти две команды, чем использовать шаблон, делающий отсечение ненужных пробелов за один раз. Поскольку процедура сопоставления шаблона и текста достаточно сложна, на эту простую операцию может уйти гораздо больше времеви, чем хотелось бы.

Например в тексте нужно найти текст, находящийся между открывающим и закрывающим тегом:

найдет все слова, стоящие между тегами и .

В регулярных выражениях пристутствует своя семантика: быстрота, торопливость и возврат. Если квантификатор * совпадает во многих случаях, то в результате быдет выведен наибольший по длинне результат. Это жадность. Быстрота: поиск старается найти как можно быстрее. "Text"=

/m*/ , по смыслу символов m нет, но в результате будет возвращено значение 0 . Т.е. формально 0 и более символов.

Читайте также:  Neoline wide s31 инструкция

$test="aaooee ooaao";
$test=

s/o*/e/;
print $test;
eaaooee ooaao

потому что 1 элемент сторки — 0 и более символов.

Если добавить квантификатор g , то результат будет таким:

т.к строка содержит 13 мест, где может встречатся o , в том числе и пустых.

Модификаторы:

  • /i игнорировать регистр
  • /x игнорировать пропуски в шаблоне и разрешить комментарии.
  • /g модификатор разрешающий выполнение поиска/замены везде, где это возможно
  • /gc не сбрасывается позиция при неудачном поиске.
  • /s разрешается совпрадение . с
    , игнорируется $* .
  • /m разрешить совпадение ^ и $ для начала и конца строки во внутренних переводах строк
  • /o однократная компиляция
  • /e правая часть s/// представляет собой выполняемый код
  • /ee правая часть s/// выполняется, после чего возвращаемое значение интерпретируется снова.

при вызове use locаle учитываются локальные настройки. Модификатор /g может заполнить массив значений @nums = m/(d+)/g; но это сработает для ненакладывающихся совпадений. Чтобы поймать совпадения нужно воспользоваться оператором ?=. Если ширина = 0 , то механизм поиска остался на прежнем месте. Найденые данные остаются внутри скобок. Если есть модификатор /g , то текущая позиция остается прежней, но происходит перемещение на один символ вперед.

Модификаторы m и s нужны для поиска последовательностей символов, содержащих перевод строки. При s точка совпадает с
и игнорируется $* . m делает совпадающими ^ и $ до и после
. e правая часть выполняется как программный код: perl -i -n -p -e ‘s/(.)/lc()/g’ *.html приводит все литеры во всех файлах *.html текущей директории к нижнему регистру.

Я пытаюсь найти подстроку и заменить всю строку, если подстрока найдена. в приведенном ниже примере someVal может быть любым значением, которое мне неизвестно.

как я могу найти someServer.com и заменить всю строку $ oldUrl и $ newUrl?

Я могу сделать это на всей строке просто отлично:

Если вы хотите совместить и заменить какой-либо субдомен, тогда вы должны разработать конкретное регулярное выражение для их соответствия.

Ниже приведена перепись вашего сценария с использованием более современных методов Perl, включая Path::Class для обработки операций с файлами и каталогами на кросс-платформенном пути и $INPLACE_EDIT чтобы автоматически обрабатывать редактирование файла.

Ваш скрипт удалит большую часть вашего контента, потому что вы окружаете его .* . Это будет соответствовать любому символу, кроме новой строки, столько раз, сколько может, от начала до конца каждой строки и заменять ее.

Функциональные возможности, которые вы используете, уже существуют в Perl, использование командной строки -pi переключается, поэтому было бы неплохо использовать его, а не пытаться создать свой собственный, который работает точно так же. Для использования редактирования на месте вам не нужен один лайнер. Вы можете сделать это:

Сценарий должен содержать определения имен и замены, а также любую необходимую проверку ошибок.

Это самое простое решение при работе с переключателями -pi , как я показал выше. Q. E — это escape-код, который ускользает от метасимволов в вашей строке (настоятельно рекомендуется).

Возможно, вы захотите предотвратить частичные совпадения. Если вы соответствуете foo.bar , вам может не foo.bar.baz или snafoo.bar . Чтобы предотвратить частичное совпадение, вы можете помещать якоря разных типов.

  • (? — не допускайте никаких пробелов перед матчем
  •  — соответствие границе слова

Граница слов подходит, если вы хотите заменить server1.foo.bar в приведенном выше примере, но не snafoo.bar . В противном случае используйте границу пробела. Причина, по которой мы делаем двойное отрицание с отрицательным утверждением и отрицательным символьным классом, — это позволить совпадение начала и конца строки.

Итак, чтобы подвести итог, я бы сделал:

И запустите его с помощью

Если вы хотите попробовать это заранее (настоятельно рекомендуется!), Просто удалите переключатель -i , который заставит сценарий печатать на стандартный вывод (ваш терминал). Затем вы можете запустить diff для файлов, чтобы проверить разницу. Например:

Вам нужно будет решить, является ли граница слова более желательной, и в этом случае вы заменяете утверждения поиска с помощью  .

Даже в маленьких сценариях, подобных этому. Это сэкономит вам время и головные боли.

Раздел: Без рубрики

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*

code