Что нового

[Данные, строки] Преобразование строки

snoitaleR

AutoIT Гуру
Сообщения
855
Репутация
223
Подскажите, пожалуйста как можно получить из строки, состоящей из фамилии, пробела, имени, пробела и отчества, получить строку, состоящюю из первого инициала, второго инициала и фамилии без пробелов...

Пробовал... Такой огород нагородил, аж самому смешно стало... :smile:

Хотелось бы оптимальное, ну, или близкое к оптимальному, решение...
 

r35p3ct

Продвинутый
Сообщения
228
Репутация
60
Код:
$a='Сидоров Иван Петррович'
$b=StringRegExpReplace($a,'(.+)\s(.).*\s(.).*','\1 \2.\3.')
ConsoleWrite($b&@LF)

Код:
Сидоров И.П.
 
Автор
snoitaleR

snoitaleR

AutoIT Гуру
Сообщения
855
Репутация
223
r35p3ct
Чуть-чуть не так... Надо "ИПСидоров"...
 

r35p3ct

Продвинутый
Сообщения
228
Репутация
60
Код:
$a='Сидоров Иван Петррович'
$b=StringRegExpReplace($a,'(.+)\s(.).*\s(.).*','\2\3\1')
;или  $b=StringRegExpReplace($a,'(.+?)\s+(.)?.*\s+(.)?.*','\2\3\1')
ConsoleWrite($b&@LF)

Код:
ИПСидоров
 
Автор
snoitaleR

snoitaleR

AutoIT Гуру
Сообщения
855
Репутация
223
r35p3ct
Спасибо... Это, наверное, оптимальный вариант... :smile: +1

Я тут тоже сочинил, правда в две строки...
Нашел функцию StringSplit()...
В регэкспах пока не очень соображаю...

Код:
$R="Иванов Иван Иванович"
$A=StringSplit($R," ")
$R=StringLeft($A[2],1)&StringLeft($A[3],1)&$A[1]
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Похоже это будет более универсальным выражением :
Код:
$a='Сидоров Иван Петрович'
$b=StringRegExpReplace($a,'(\S*)\s*(\S)?\S*\s*(\S)?\S*','\2\3\1')
ConsoleWrite($b&@LF)


Оно позволит выдать выдавать :
Код:
ИСидоров      при отсутствии отчества 
и 
Сидоров       при отсутствии имени-отчества
а также учитывает возможность ошибки(2 пробела вместо одного)
 

amel27

Продвинутый
Сообщения
146
Репутация
55
еще вариант:

Код:
$s1 = "Сидоров Иван Петрович"
$s2 = "Сидоров Иван"
$s3 = "Сидоров"

$r = "^(\S++)(?:\s++(\S)\S*+)?(?:\s++(\S)\S*+)?$"

$s1 = StringRegExpReplace($s1, $r, "$2$3$1")
$s2 = StringRegExpReplace($s2, $r, "$2$3$1")
$s3 = StringRegExpReplace($s3, $r, "$2$3$1")

ConsoleWrite($s1 &@CRLF)
ConsoleWrite($s2 &@CRLF)
ConsoleWrite($s3 &@CRLF)
 
Автор
snoitaleR

snoitaleR

AutoIT Гуру
Сообщения
855
Репутация
223
amel27
Я могу регэкспы оценивать только по результату... :-[
Скажи, пожалуйста, в чем разница между твоим регэкспом и регэкспом, предложенным gregaz?
 

amel27

Продвинутый
Сообщения
146
Репутация
55
snoitaleR сказал(а):
в чем разница между твоим регэкспом и регэкспом, предложенным gregaz?

в поведении при передаче ошибочных строк - мой вариант будет преобразовывать только строки заданного формата (описанного в регулярном выражении), во всех остальных случаях замены не производятся (@Extended=0), вариант gregaz будет производить замены ВСЕГДА, т.к. ни одно из подвыражений не является обязательным и неизвестно какое из них и когда сработает:

Код:
$s1 = "Сидоров Иван Петрович Ибн Хасан"
$s2 = " Сидоров Иван"
$s3 = " Сидоров"

$r = "(\S*)\s*(\S)?\S*\s*(\S)?\S*"

$s1 = StringRegExpReplace($s1, $r, "$2$3$1")
$s2 = StringRegExpReplace($s2, $r, "$2$3$1")
$s3 = StringRegExpReplace($s3, $r, "$2$3$1")

ConsoleWrite($s1 &@CRLF)
ConsoleWrite($s2 &@CRLF)
ConsoleWrite($s3 &@CRLF)


З.Ы. регулярные выражения, где все элементы необязательные (*) не есть хорошо... :whistle:
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
amel27 сказал(а):
в поведении при передаче ошибочных строк - мой вариант будет преобразовывать только строки заданного формата (описанного в регулярном выражении), во всех остальных случаях замены не производятся
Поскольку я только начал изучать Регэкспы просьба разъяснить :
Какое поведение Регэкспа при ошибке лучше?
1. Не преобразовывать строку
2. Все равно постараться преобразовать в правильном формате.
Твой вариант ошибочные строки -не преобразует и что в этом хорошего ?
Ведь если обрабатывать много строчек в результирующий список попадут и не обработанные.
Мой вариант чуть измененный и для случаев :
Код:
$s1 = "Сидоров Иван Петрович Ибн Хасан"
$s2 = " Сидоров Иван"
$s3 = " Сидоров"

;$r = "(\S*)\s*(\S)?\S*\s*(\S)?\S*"
$r = "\s*(\S*)\s*(\S)?\S*\s*(\S)?.*"

$s1 = StringRegExpReplace($s1, $r, "$2$3$1")
$s2 = StringRegExpReplace($s2, $r, "$2$3$1")
$s3 = StringRegExpReplace($s3, $r, "$2$3$1")

ConsoleWrite($s1 &@CRLF)
ConsoleWrite($s2 &@CRLF)
ConsoleWrite($s3 &@CRLF)

выдаст правильный результат ,тогда как твой выдаст необработанные строки
Он также првильно обработает и строки с пробелами в конце :
Код:
$s1 = "Сидоров  Иван   Петрович  "
$s2 = " Сидоров Иван  "
$s3 = " Сидоров  "
Попутно просьба рассмотреть правильность получения рез-та в виде : И.П.Сидоров И.Сидоров
Код:
$s1 = "Сидоров Иван Петрович"
$s2 = "Сидоров Иван"
$s3 = "Сидоров"
$s4 = "  Сидоров Иван   Петрович Ибн Хасан"
$s5 = "  Сидоров   Иван "
$s6 = "  Сидоров "

; $r = "^(\S++)(?:\s++(\S)\S*+)?(?:\s++(\S)\S*+)?$"
$r = "^\s*(\S++)(?:\s++(\S)\S*+)?(?:\s++(\S)\S*+)?.*$"
$r1='(?:^\.\.|\.(\.))'

$s1 = StringRegExpReplace(StringRegExpReplace($s1, $r, "$2.$3.$1"),$r1, "$1")
$s2 = StringRegExpReplace(StringRegExpReplace($s2, $r, "$2.$3.$1"),$r1, "$1")
$s3 = StringRegExpReplace(StringRegExpReplace($s3, $r, "$2.$3.$1"),$r1, "$1")
$s4 = StringRegExpReplace(StringRegExpReplace($s4, $r, "$2.$3.$1"),$r1, "$1")
$s5 = StringRegExpReplace(StringRegExpReplace($s5, $r, "$2.$3.$1"),$r1, "$1")
$s6 = StringRegExpReplace(StringRegExpReplace($s6, $r, "$2.$3.$1"),$r1, "$1")

ConsoleWrite($s1 &@CRLF)
ConsoleWrite($s2 &@CRLF)
ConsoleWrite($s3 &@CRLF)
ConsoleWrite($s4 &@CRLF)
ConsoleWrite($s5 &@CRLF)
ConsoleWrite($s6 &@CRLF)

Насолько корректно и оптимально оно ?




Добавлено:
Сообщение автоматически объединено:

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

amel27

Продвинутый
Сообщения
146
Репутация
55
gregaz сказал(а):
Какое поведение Регэкспа при ошибке лучше?
Зависит от задачи - не всегда есть возможность просчитать все возможные варианты (правильные и ошибочные), в данном случае всё просто, т.к. использовано всего два взаимоисключающих класса "\s" и "\S".

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

Код:
$s = ""
$r = "\s*(\S*)\s*(\S)?\S*\s*(\S)?.*"

$s = StringRegExpReplace($s, $r, "$2$3$1")

ConsoleWrite('замен: '& @extended &@CRLF)
ConsoleWrite('результат: "'& $s &'"'&@CRLF)


gregaz сказал(а):
Попутно просьба рассмотреть правильность получения рез-та в виде: И.П.Сидоров И.Сидоров
скажем, хде-то так:

Код:
$r = "^\s*(\S++)(?:\s++(\S)\S*+)?(?:\s++(\S)\S*+)?.*$"
$r1='(?:^\.++|(\.)++)'


gregaz сказал(а):
Похоже мне стало ясно одно правило : При составлении Регэкспа надо избежать неправильной обработки . Несовпадающие с шаблоном строки должны выдаваться в необработанном виде.
главное - управляемость выражения и предсказуемость результата (как и в любом другом языке программирования)
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
amel27 , Спасибо
Можно еще вопрос ?
У тебя практически не используется символ : "*" и "+"
Когда можно использовать "*" и "+" , а когда "*+" и "++"
Если можно просьба разъяснить попроще , может на характерном примере
 

amel27

Продвинутый
Сообщения
146
Репутация
55
gregaz сказал(а):
Когда можно использовать "*" и "+" , а когда "*+" и "++"
Если можно просьба разъяснить попроще , может на характерном примере
в моем примере захватывающие квантификаторы использованы для оптимизации, т.к. работают существенно быстрее, но есть задачи, где они закладываются в сам алгоритм разбора

Код:
; Попробуем вернуть слово без знака препинания "!"
$s = "Ура!"

; "\S+" захватывает все символы до конца строки,
; но потом вынужден отдать один символ "!"
$w = StringRegExpReplace($s, "(\S+)[.,:;!?]", "$1")
$x = @extended
ConsoleWrite($w &@CRLF)
ConsoleWrite("замен: "& $x &@CRLF)

; "\S++" захватывает все симаолы до конца строки,
; но отдавать обратно не намерен, поэтому "!"
; оказывается "лишним" и дает несовпадение
$w = StringRegExpReplace($s, "(\S++)[.,:;!?]", "$1")
$x = @extended
ConsoleWrite($w &@CRLF)
ConsoleWrite("замен: "& $x &@CRLF)

; Исправленный вариант для "++",
; знак "!" исключен из класса
$w = StringRegExpReplace($s, "([^\s.,:;!?]++)[.,:;!?]", "$1")
$x = @extended
ConsoleWrite($w &@CRLF)
ConsoleWrite("замен: "& $x &@CRLF)
 

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
amel27 ,Огромное спасибо за разъяснения. Весьма популярно.
Не перестаю удивляться богатым возможностям Регулярных выражений
 
Верх