Регулярное выражение Notepad ++ выбирает полный файл, когда совпадение отсутствует

Это мой первый вопрос, поэтому, пожалуйста, поддержите меня, пока я попытаюсь написать его как можно аккуратнее и полнее!

Я пытаюсь выполнить поиск и замену в Notepad++ с помощью регулярного выражения, но получаю странные результаты, которых не понимаю. Может кто-нибудь объяснить, где я ошибаюсь и что я могу сделать, чтобы достичь желаемого результата, пожалуйста?

Я использую Notepad++ версии 6.8.3.

У меня есть несколько файлов журналов, в которых необходимо отредактировать любую информацию о клиентах. Мне нужно найти текст Name: и заменить все после него на *REDACTED* Это нужно сделать с помощью «Заменить в файлах». Ниже приведен пример конкретных случаев:

applicantDetailsCommand.firstName: Arnold 
blah blah blah blah blah blah blah blah blah blah blah
applicantDetailsCommand.middleName: Judas
applicantDetailsCommand.lastName: Rimmer
blah blah blah blah blah blah blah blah
blah blah blah blah
applicantDetailsCommand.firstName: Dave 
applicantDetailsCommand.middleName: Cinzano Bianco
applicantDetailsCommand.lastName: Lister
blah blah blah blah blah blah
blah blah blah

Чтобы сделать это, я начал поиск, используя поиск позади, таким образом: (?<=Name: ).*$, который работал нормально и нашел все записи после firstName, lastName и т. д. Однако в любом файле, который не содержал «Имя:», весь файл соответствовал включая все строки, поэтому я не могу использовать это в «Заменить в файлах», так как он просто заменит весь файл на «*УДАЛЕНО*».

Затем я попытался сопоставить строку без использования просмотра назад, поэтому искал (Name: ).*$ и собирался заменить его на $1\*REDACTED\*, что сработало, но я также обнаружил, что он нашел несколько других строк, таких как «host_name» и « URIName", чего я не хотел.

В этот момент я решил использовать группу только с той альтернативой, которую я действительно хотел сопоставить, поэтому попробовал это: (first|middle|last|account)Name: .*$, который начал сопоставлять полные файлы, когда в файле не было ни accountName, ни firstName, ни middleName, ни lastName.

Я прочитал множество разных статей на tinterweb, но не могу найти ничего, что объясняло бы, почему при отсутствии совпадения сопоставляется полный файл.

Любая помощь, объясняющая это, будет высоко оценена.

Большое спасибо.


person Begbie007    schedule 02.12.2015    source источник
comment
Что, если вы сделаете фактический шаблон имени более конкретным? Вместо .* что-то вроде: \w+(?:\s+\w+)?   -  person MattDG    schedule 02.12.2015
comment
К сожалению, это дает мне тот же результат. Спасибо за ваш вклад, хотя, я не пробовал это.   -  person Begbie007    schedule 02.12.2015
comment
Еще одна мысль может заключаться в том, чтобы попробовать это в Perl или Python. Может быть, это просто ошибка в NP++...?   -  person MattDG    schedule 02.12.2015
comment
Когда вы запускаете (first|middle|last|account)Name: .*$ при поиске всех файлов, вы говорите, что он сообщает, что он соответствует полным файлам. Это похоже на ошибку, если вы отключили совпадения с новой строкой, поскольку для каждого совпадения должны сообщаться номера строк. Ваше регулярное выражение кажется прекрасным. Возможно, вам стоит обновиться до 6.8.7?   -  person waynethec    schedule 02.12.2015
comment
Да, когда я выполняю поиск в файлах, оба поиска с ошибками соответствуют всем элементам, которые должны быть, но там, где есть файл без совпадений, он соответствует всему файлу от начала до конца.   -  person Begbie007    schedule 02.12.2015


Ответы (4)


Это действительно ошибка - после долгих поисков я в конце концов нашел это на GitHub: https://github.com/notepad-plus-plus/notepad-plus-plus/issues/683

Кажется, это происходит только при использовании группировки и файлов определенной длины. В одном файле разделение его на два позволило мне не найти совпадений (?<=\d{8}(,|:) ).*?(?=>|\)), в то время как сохранение файла в целом привело к тому, что регулярное выражение выбрало весь файл. Странно, хотя поиск (?<=\d{4}(,|:) ).*?(?=>|\)) в тех же файлах работал нормально - где длина цифр в первой группе была 4 вместо 8, в остальном идентично!

Кроме того, в другом поиске я изменил одно из исходных регулярных выражений в своем вопросе с (first|middle|last|account)Name: .*$ на (first|middle|last)Name: .*$, и это также начало работать, как и сохранение того же регулярного выражения и уменьшение длины файла вдвое. Я также попробовал (rst|dle|ast|unt)Name: .*$, который не удался, и (first|middle|account)Name: .*$, который сработал, все они довольно случайны и не могут быть привязаны к какой-либо одной проблеме.

Это наводит меня на мысль, что в механизме регулярных выражений есть фундаментальная проблема, и в результате мы отказываемся от Notepad++ в качестве решения и покупаем вместо него что-то другое, поскольку нельзя полагаться на правильность механизма регулярных выражений.

Надеюсь, это поможет кому-то.

person Begbie007    schedule 16.12.2015

Убедитесь, что вы сняли флажок «. находит \r и \n» в окне «Поиск и замена».

person Wormbo    schedule 02.12.2015
comment
Привет, извините - я должен был сказать, что я отключил флажок новой строки .matches, который, как я полагаю, то же самое? Спасибо - person Begbie007; 02.12.2015

Найдите что: Name: .*
Замените на: Name: *REDACTED*

Этот метод должен работать, даже если вы добавите группу (first|middle|last|account) перед шаблоном Find what. Точные настройки смотрите на картинках ниже: (кстати, я использую версию 6.8.6)

Что происходит, когда файл содержит ваш поиск:

И что происходит, когда это не так:

person SeinopSys    schedule 02.12.2015
comment
Это работает для меня, когда у меня есть совпадение, но не когда совпадений нет - выделяется весь файл. Размер файла достаточно 140 МБ, поэтому не уверен, что это влияет на него, но если я ищу имя, фамилию, имя учетной записи или отчество самостоятельно, совпадения не будет. Возможно, это ошибка в версии, которую я использую? - person Begbie007; 02.12.2015

Удалите $, потому что обычно это означает конец строки, если не используется многострочный режим.

Однако вам не нужен многострочный режим. И вам нужно отключить ВЫКЛ
. Точка означает все символы, поэтому она будет соответствовать чему угодно, кроме разрывов строк.

Наконец, использование (?<=Name: ).*$ может привести к проблемам с возвратом, если Name:
не найдено.

Забудьте о ретроспективе, заставьте ее найти: Name:\h.* Заменить Name: REDACTED

person Community    schedule 02.12.2015
comment
Хороший вопрос, я не думал о том, что .* останавливается на разрыве строки. При этом последняя часть регулярного выражения работает, когда есть совпадение, чего я и ожидал, но я никогда не думал о том, как оно отреагирует, если совпадения не будет. Я попробую это, когда я приду на работу утром. У вас есть пример или объяснение проблем с возвратом, если вы не возражаете? Я хотел бы понять, почему это происходит, а не просто исправить это для меня. Спасибо. - person Begbie007; 02.12.2015
comment
@ Begbie007 — когда вы определяете утверждение, содержимое всегда запускается как отдельный контекст, удаленный от окружающего контекста. Он просто возвращает истину или ложь вызывающей стороне. Это означает, что окружающий контекст не может быть оптимизирован как единый контекст. Таким образом, открывается дверь для потенциальных проблем с возвратом. Вот почему что-то вроде этого .*(Name: ).*$ сразу выходит из строя, а что-то вроде этого .*(?<=Name: ).*$ занимает экспоненциально больше времени. Как правило, не очень хорошо размещать обратные связи в точке, где она открыта (.* с любой/двух сторон). - person ; 03.12.2015
comment
Спасибо за объяснение, я понимал, что использование поиска займет больше времени, но не понимал, что открывать их с открытым концом было плохой идеей. Я попробовал ваше предложение, но вижу те же результаты, что и раньше, когда Name:\h.* работает, но выбирает слишком много. И когда я пытаюсь (account|first|middle|last)Name:\h.*, выбирается весь файл без совпадений вместе с разрывами строк, хотя я не выбрал . соответствует новой строке. - person Begbie007; 03.12.2015
comment
Я никогда не использовал np++, но я понимаю, что в большинстве движков по умолчанию точка не соответствует разрыву строки. в худшем случае вы сможете использовать (?-s)(Name: ).*, который использует встроенный модификатор для отключения off dot-all. Встроенные модификаторы имеют область действия, поэтому они переопределяют любые глобальные флаги. Если это не сработает, я бы не стал использовать np++ , это полный мусор. Еще одна вещь, которую стоит попробовать, это (Name: )[^\r\n]*, где [^\r\n] (почти) совпадает с (?-s). - person ; 05.12.2015
comment
Еще раз спасибо за повтор. Теперь я установил NP++ 6.8.7, и (account|first|middle|last)Name:\h.* теперь работает, так что это, очевидно, ошибка в механизме регулярных выражений. (Name: )[^\r\n]* тоже работает в этой версии, спасибо за это. Будучи моим первым вопросом, я не уверен, что мне делать с этим сейчас. Должен ли я ответить и сказать, что это ошибка? По какой-то причине он уже был уценен, есть ли способ узнать, почему? Еще раз спасибо за ваш вклад. - person Begbie007; 09.12.2015
comment
На случай, если кто-то читает эту ветку - установка последней версии не сработала. Он по-прежнему не работает с файлами определенного размера. Я попытался разделить один из моих тестовых файлов на два, и он отлично работает для обеих половин (независимо от того, где находится разделение), но терпит неудачу и выбирает/заменяет полный файл, когда он превышает ~ 21500 строк (не уверен в размере Мб) , поэтому кажется ошибкой при определенных обстоятельствах. - person Begbie007; 16.12.2015