Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Распределить ссылки (http://forum.oszone.net/showthread.php?t=346402)

ateka 10-09-2020 23:42 2933636

Распределить ссылки
 
Здравствуйте, пытаюсь решить задачу но не знаю как.
На вход скрипта приходят URL трёх видов:
Код:

https://site.com/user/anything/anything
https://anything.site.com/anything-anything-12345678/anything
https://anything.site.com/

Из первого мне нужен только user
Из второго только цифры (они всегда разные)
Из третьего только субдомейн (в данном случае anything)
это я знаю как сделать.
После в каждом конкретном случае мне нужно сформировать URL и открыть в браузере.
И тут у меня ступор. Каким образом решаются подобные задачи?
Как сделать так что бы скрипт различал что это ссылка на пользователя, пост или субдомейн
и запускал на исполнение соответствующую сабрутину?
Заранее благодарю.

Foreigner 11-09-2020 00:47 2933640

PowerShell:

Код:

$urls = 'https://site.com/user/anything/anything',
        'https://anything.site.com/anything-anything-12345678/anything',
        'https://anything.site.com/'

$user, $post, $sub = $urls -replace '.+//[^./]+\.[^/]+/([^/]+)/.+','$1' -replace '\D+(\d+)/.+','$1'
       
$user
$post
$sub


Fors1k 11-09-2020 02:28 2933643

Foreigner, У меня не сработало:
Цитата:

user
anything-anything-12345678
https://anything.site.com/
Код:

$urls = 'https://site.com/user/anything/anything',
        'https://anything.site.com/anything-anything-12345678/anything',
        'https://anything.site.com/'
cls
$user = ($urls|sls "(?<=(?<!\..+)\.[^\.]+?/)[^/]+(?!.*-\d/)").Matches.Value
$sub  = ($urls|sls "[^/]+?(?=\.(?=.+\.)[^/]+/$)").Matches.Value
$post = ($urls|sls "(?<=-)\d+").Matches.Value

"https://$sub.site.com/$user/$post"

Адова регулярка (с) DJ Mogarych, но на ночь глядя ничего красивее не стал искать)

Foreigner 11-09-2020 07:23 2933649

Цитата:

Цитата Fors1k
У меня не сработало »

Это я перепутал вариант:
Код:

$urls = 'https://site.com/user/anything/anything',
        'https://anything.site.com/anything-anything-12345678/anything',
        'https://anything.site.com/'

$user, $post, $sub = $urls -replace '.+//[^./]+\.[^/]+/([^/]+)/.+','$1' `
                          -replace '\D+(\d+)','$1' `
                          -replace '.+//([^./]+).+', '$1'
       
"https://$sub/$user/$post"


Vadikan 11-09-2020 08:44 2933657

PowerShell
В данном случае в качестве альтернативы регулярному выражению можно использовать оператор -Split - это попроще для непосвященных кмк (по кр. мере на простых примерах, объяснял тут https://www.outsidethebox.ms/19453/).

Код:

$urls = 'https://site.com/user/anything/anything',
        'https://anything.site.com/anything-anything-12345678/anything',
        'https://anything.site.com/'
               
$user = $urls[0].split('/')[3]
$post = ($urls[1].split('/')[3]).split('-')[2]
$sub = ($urls[2].split('/')[2]).split('.')[0]
"https://$sub.site.com/$user/$post"


Fors1k 11-09-2020 10:42 2933668

Цитата:

Цитата Vadikan
можно использовать оператор -Split »

Цитата:

Цитата ateka
Как сделать так что бы скрипт различал что это ссылка на пользователя, пост или субдомейн »

Split конечно проще, но автор не знает как отличить ссылки друг от друга. Это говорит о том, что порядок ссылок заранее не известен.
Foreigner, тоже не сработает для другого порядка.

ateka 11-09-2020 11:23 2933677

Друзья, я дико извиняюсь что был неясен и ввёл вас в заблуждение. Просто эта задача сломала мне остатки мозга. На вход скрипта приходит одного из трёх видов. И в зависимости от вида url я его обрабатываю нужным образом.
Код:

if _url==https://site.com/user/anything/anything goto usercheck
else
if _url==https://anything.site.com/anything-anything-12345678/anything goto postcheck
else
if _url==https://anything.site.com/ goto subdomaincheck
else goto error

За регулярки огромное спасибо я как раз думал в эту сторону но сам не осилил.

Foreigner 11-09-2020 11:50 2933679

Цитата:

Цитата Fors1k
тоже не сработает для другого порядка. »

Возможно, Select-String тогда полезен, хоть и надо тестировать в любом случае. С урлами выкрутасы еще те.

Fors1k 11-09-2020 12:34 2933688

Цитата:

Цитата ateka
На вход скрипта приходит одного из трёх видов »

Код:

$urls = (
    'https://site.com/user/anything/anything',
    'https://anything.site.com/anything-anything-12345678/anything',
    'https://anything.site.com/'
)|Get-Random;cls


$search = @{
    postID    = "(?<=-)\d+"
    userID    = "(?<=(?<!\..+)\.\w+?/)[^/]+"
    subDomain = "[^/]+?(?=\.(?=.+\.)[^/]+/$)"
}
$search.keys|%{
    if($i=($urls|SLS $search[$_]).Matches.Value){
        nv $_ $i -F;"В ссылке было:";gv $_|ft -hi
    }
}


megaloman 11-09-2020 16:00 2933711

Цитата:

Цитата ateka
На вход скрипта приходит одного из трёх видов. И в зависимости от вида url я его обрабатываю нужным образом. »

Длинно, но зато CMD
Код:

@Echo Off
cls
        Set "URL=https://site.com/user/anything/anything"
        Call :DefOut "%URL%" "Log" "Out"
        Call :Sub%Log% "%URL%" "%Log%" "%Out%"

        Set "URL=https://anything.site.com/anything-anything-12345678/anything"
        Call :DefOut "%URL%" "Log" "Out"
        Call :Sub%Log% "%URL%" "%Log%" "%Out%"

        Set "URL=https://anything.site.com/"
        Call :DefOut "%URL%" "Log" "Out"
        Call :Sub%Log% "%URL%" "%Log%" "%Out%"
pause
Exit /B

:Sub1
        Echo =======
        Echo Вариант %2: user
        Echo %1
        Echo %3
        Echo.
Exit /B

:Sub2
        Echo =======
        Echo Вариант %2: Цифры
        Echo %1
        Echo %3
        Echo.
Exit /B

:Sub3
        Echo =======
        Echo Вариант %2: Субдомен
        Echo %1
        Echo %3
        Echo.
Exit /B

:DefOut
SetLocal
        Set "In=%~1"
        Set "In=%In:*//=%"
        Set "Reg=-[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]"
       
        FOR /F "tokens=1,2 delims=/" %%s IN ("%In%") DO (
                If "%%t"=="" (
                        FOR /F "tokens=1 delims=." %%a IN ("%In%") DO (
                                EndLocal &(Set /A %~2=3 &Set "%~3=%%a" &Exit /B 3)
                        )
                )
                Set "In2=%%t"
                Call Set "In2=%%In2:~-9%%"
                Echo %%t|findstr /E /R /C:"%Reg%">nul||(
                        EndLocal &(Set /A %~2=1 &Set "%~3=%%t" &Exit /B 1)
                )
        )
        Echo %In2%|findstr /E /R /C:"%Reg%">nul&&EndLocal &(Set /A %~2=2 &Set "%~3=%In2:~-8%" &Exit /B 2)
EndLocal &(Set /A %~2=0 &Set "%~3=" &Exit /B 0)       
Exit /B


Vadikan 11-09-2020 17:28 2933717

Цитата:

Цитата Fors1k
но автор не знает как отличить ссылки друг от друг »

Перечитал исходный пост - да, неправильно понял:)

greg zakharov 11-09-2020 17:29 2933718

Ответ на оригинальный вопрос.
Код:

[Uri[]]$u = 'https://site.com/user/anything/anything','https://anything.site.com/anything-anything-12345678/anything','https://anything.site.com/'
"https://$(($$ = $u[2].Host).Substring(0, $$.IndexOf('.'))).site.com/$(-join$u[0,1].ForEach{$_.Segments[1].Split('-')[-1]})"


Что касается сценариев разбора, если количество сегментов в URL всегда фиксировано:
Код:

[Uri[]]$u = 'https://site.com/user/anything/anything','https://anything.site.com/anything-anything-12345678/anything','https://anything.site.com'
# массив сценариев (скрипт-блоков), что нужно сделать в том или ином случае
$scenario = {'subdomaincheck'},{},{'postcheck'},{'usercheck'}
$u.ForEach{$scenario[$_.Segments.Count - 1]}

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

#requires -version 7
function Get-UrlType {
  [CmdletBinding(DefaultParameterSetName='Url')]
  param(
    [Parameter(Mandatory, ParameterSetName='Url', Position=0)]
    [ValidateNotNullOrEmpty()]
    [Uri[]]$Url,

    [Parameter(Mandatory, ParameterSetName='Raw', Position=0)]
    [ValidateNotNullOrEmpty()]
    [String[]]$Raw
  )

  end {
    $scope = $PSCmdlet.ParameterSetName -eq 'Raw' ? [Uri[]]$Raw : $Url
    $scope.ForEach{
      $_.Host.Split('.').Count -eq 2 ? $(
        'User: {0}' -f $_.Segments[1].Trim('/')
      ) : $(
        $_.Segments.Count -eq 1 ? $(
          'Subdomain: {0}' -f $_.Host.Substring(0, $_.Host.IndexOf('.'))
        ) : $(
          'Code: {0}' -f $_.Segments[1].Split([Char[]]@('-', '/'))[-2]
        )
      )
    } # foreach
  }
}

Вне зависимости от того, передаётся ли в функцию массив URI или просто строк, функция будет обрабатывать поступающие на вход данные как URI. В цикле для каждого элемента массива, передаваемого функции, выстраивается следующая логика:
1) если хост назначения состоит из двух элементов (вида site.com), следовательно в данном URL ищем юзера
2) в противном случае, если количество сегментов - единица, искать субдомен
3) иначе вытащить из второго сегмента URL цифровое значение
Таким образом:
Код:

$u = 'https://site.com/user/anything/anything',
    'https://anything.site.com/anything-anything-12345678/anything',
    'https://anything.site.com'
Get-UrlType $u

Выдаст:
Код:

User: user
Code: 12345678
Subdomain: anything

Альтернативное решение задачи, при условии, что site.com во всех трёх случаях постоянно, можно представить через объединение URI с "хирургией" через обобщённый делегат. Правда это уже более функциональный стиль, а здесь, на форуме, повсеместно императивщина.

YuS_2 11-09-2020 19:01 2933725

Цитата:

Цитата ateka
На вход скрипта приходят URL трёх видов »

Код:

$urls = 'https://anything.site.com/',
        'https://site.com/user/anything/anything',
        'https://anything.site.com/anything-anything-12345678/anything'

$urls|%{
        $url = [uri]$_
        if ($url.segments.count -gt 1) {
                if ($url.segments[1] -match '-\d+($|/)') {
                        $digits = $url.segments[1].split('-')[-1] -replace '/'
                } else {$user = $url.segments[1] -replace '/'}
        } else {$subdomen = $url.host.split('.')[0]}
}
$subdomen
$user
$digits

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

greg zakharov 11-09-2020 19:15 2933726

YuS_2, см. выше

Fors1k 11-09-2020 19:29 2933731

Цитата:

Цитата YuS_2
строго ли их по три за один проход поступает »

Цитата:

Цитата ateka
На вход скрипта приходит одного из трёх видов »


YuS_2 11-09-2020 20:43 2933735

Цитата:

Цитата greg zakharov
YuS_2, см. выше »

угу, страница обновилась уже после отправки и потом увидел, что, по сути, тот же принцип... но подумал, пусть останется, как вариант, лишним не будет. :)
У тебя, кстати, скрипт ограничен версией powershell 7.0, что не есть хорошо, имхо...


Fors1k,
это малоинформативное условие, ибо если приходит одна из трех видов, то логично предположить, что следующим ходом приходит ещё одна ссылка из трех видов и т.д.
Но вот последовательность поступления неясна, т.к. по такому условию допустим вариант, что подряд могут поступать ссылки одного типа неоднократно.
Например, так:
Код:

'https://site.com/user/anything/anything'
'https://site.com/user/anything/anything'
'https://site.com/user/anything/anything'
'https://site.com/user/anything/anything'

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

Fors1k 11-09-2020 20:52 2933737

Я так понимаю, что ссылки уже готовы для каждого случая, за исключением одного пробела.
Приходит одна ссылка, получаем переменную, открываем в браузере. И так может хоть сто раз прийти одна ссылка, но с разными переменными:
Цитата:

'https://site.com/Fors1k/anything/anything'
'https://site.com/YuS_2/anything/anything'
'https://site.com/greg_zakharov/anything/anything'
Вот такой вариант решения
Код:

[Uri[]]$u = (
    'https://site.com/user/anything/anything',
    'https://anything.site.com/anything-anything-12345678/anything',
    'https://anything.site.com/'
)|Get-Random;cls

$IFuser={
    $user=$u.Segments[1].Trim("/")
    write-host "Ссылка на пользователя: $user"
    start "https://XYZ.com/$user/anything/anything"
}
$IFsub ={
    $sub =$u.host.split('.')[0]
    write-host "Ссылка на субдомен: $sub"
    start "https://$sub.XYZ.com/"
}
$IFpost={
    $post=$u.Segments[1].split(("/","-"))[-2]
    write-host "Ссылка на пост: $post"
    start "https://abc.XYZ.com/anything-anything-$post/anything"
}
switch($u.Segments.Count){1{&$ifsub}4{&$ifuser}3{&$ifpost}}


greg zakharov 11-09-2020 21:09 2933739

Цитата:

Цитата YuS_2
скрипт ограничен версией powershell 7.0, что не есть хорошо, имхо...

С чего бы? Там, если так незаметно, используется тернарная операция, которая появилась в семерке, а директива #requires -version 7 только это подчёркивает, дабы не возникало вопросов, дескать, не работает и дыр и пыр в оном духе. Ко всему прочему, давайте начистоту. PowerShell в основе которого лежит платформа .NET Framework де-юре может использоваться, но де-факто - труп, а трупов пинать нехорошо. Так что имхай, не имхай, но как раз оглядка на обратную совместимость - большая ошибка (как и основной тормоз в плане мигрирования на pwsh, ибо в последнем куда более полезных фич. Например, использование указателей в динамических методах, что на примере большого объема данных (не говоря о критичности по времени исполнения) просто пиндыр как важно; перечислять все достоинства от использования самой актуальной версии, полагаю, смысла не имеет. Всё вскрывается на практике. А на практике pwsh способен на многое - это серьёзный аргумент нежели "имхо".

Fors1k, вы желаете вооружённого конфликта?
Цитата:

Цитата Fors1k
Я так понимаю, что ссылки уже готовы для каждого случая, за исключением одного пробела.

С идеологической точки зрения URL вообще должны кодироваться escape:
Код:

[Uri]::EscapeDataString('https://site.com/name lastname/other')
И что это за crapcode со свитчем?

YuS_2 11-09-2020 21:24 2933741

Цитата:

Цитата Fors1k
Приходит одна ссылка, получаем переменную, открываем в браузере. »

этого не было в условии...
Было:
Цитата:

Цитата ateka
Из первого мне нужен только user
Из второго только цифры (они всегда разные)
Из третьего только субдомейн (в данном случае anything)
...
После в каждом конкретном случае мне нужно сформировать URL и открыть в браузере.
»

Так что, тут ссылка открывается в браузере, только после получения трех отдельных единиц данных...

Цитата:

Цитата greg zakharov
С чего бы? »

Хотя бы из того, что не везде есть возможность его установки... по разным причинам.

Цитата:

Цитата greg zakharov
Там, если так незаметно, используется тернарная операция, которая появилась в семерке »

объяснение этого вовсе не требовалось, ибо достаточно заметно... :yes:
И с остальным согласен, но увы... без особой необходимости использования того самого тернарного оператора, получаем искусственное ограничение использования скрипта.
Ну а что поделать, если у микрософта не хватило мозгов/желания/внимания, для реализации данного оператора с первых версий powershell? Видимо, исходили из того, что условный оператор его вполне заменяет...

Цитата:

Цитата greg zakharov
перечислять все достоинства от использования самой актуальной версии, полагаю, смысла не имеет. »

никакого, ибо достаточно очевидно...

greg zakharov 11-09-2020 21:46 2933746

Цитата:

Цитата YuS_2
Хотя бы из того, что не везде есть возможность его установки... по разным причинам.

То же можно сказать, например, и про Python. Так что всё относительно.

Iska 11-09-2020 22:06 2933748

Цитата:

Цитата greg zakharov
Ко всему прочему, давайте начистоту. PowerShell в основе которого лежит платформа .NET Framework де-юре может использоваться, но де-факто - труп, а трупов пинать нехорошо. Так что имхай, не имхай, но как раз оглядка на обратную совместимость - большая ошибка (как и основной тормоз в плане мигрирования на pwsh, ибо в последнем куда более полезных фич. »

«А я, сынок, всё одну, одну…»™ :).

DJ Mogarych 11-09-2020 22:39 2933751

Powershell:
Код:

$url = (Read-Host "URL").trim() -replace '/$'

if ($url -match '\d{8}') {"Цифры"}
elseif ($url.Split('/')[2] -match "\..*?\.") {"Субдомен"}
else {"Юзер"}


greg zakharov 12-09-2020 00:21 2933759

DJ Mogarych, если цифра восьмизначная, в общем-то можно жахать регуляркой, а вот по части сплитов, тримов и репласов... Вот поэтому лучше использовать URI.
Код:

[Uri[]]$u = 'https://site.com/user/anything/anything',
      'https://anything.site.com/anything-anything-12345678/anything',
      'https://anything.site.com'
$u.ForEach{$_ -match '\d{8}' ? 'number' : $_.PathAndQuery -eq '/' ? 'subdomain' : 'user'}

Если бы автор темы предоставил более входящих данных, не пришлось бы гадать что да как должно быть.

DJ Mogarych 12-09-2020 13:06 2933792

Код:

[uri]
Прикольная штука!

ateka 12-09-2020 14:25 2933796

Спасибо вам небожители что снисходите со своей помощью к нам - простым смертным.
Без вас я бы точно не справился. И так много ответов.
Теперь буду сидеть с словариком эльфийского гуглом разбираясь в пош коде.
Спасибо большое.

greg zakharov 13-09-2020 15:10 2933875

Хотя megaloman уже предлагал решение на командном языке, сам он посетовал на объём кода. В принципе, кое-какие моменты им были намечены правильно (например, регулярка для восьмизначного числа), но многое можно нивелировать.
Код:

@echo off
  setlocal enabledelayedexpansion
    :: массив ссылок, индексация начинается с единицы
    set "url.1=https://site.com/user/anything/anything"
    set "url.2=https://anything.site.com/anything-anything-12345678/anything"
    set "url.3=https://anything.site.com"
    :: перебираем массив URL'ов
    call:foreach "set url"
  endlocal
exit /b

:foreach
  for /l %%i in (1,1,3) do (
    (%~1.%%i|>nul findstr /rc:"-[0-9]*/")&&(echo:%%~i - number)||(
      for /f "tokens=2,3 delims=/" %%j in ('%~1.%%i') do (
        if [%%k] neq [] (
          echo:%%~i - user
        ) else echo:%%~i - subdomain
      )
    )
  )
exit /b

После запуска сценария, получим:
Код:

1 - user
2 - number
3 - subdomain

Если перетасовать элементы массива, например, так:
Код:

    ...
    set "#=!url.1!"
    set "url.1=!url.3!"
    set "url.3=!url.2!"
    set "url.2=!#!"
    :: выводим изменённый массив
    set url
    :: снова перебираем массив
    call:foreach "set url"
    ...

Получим:
Код:

url.1=https://anything.site.com
url.2=https://site.com/user/anything/anything
url.3=https://anything.site.com/anything-anything-12345678/anything
1 - subdomain
2 - user
3 - number

Очевидно, что корректность зависит от токенов и регулярки. Это что касается решения задачи штатными средствами. Относительно сторонних программ\платформ\утилит: очень просто URL'ы разбираются jq, node и минишеллами вроде miniperl или miniruby, а также gawk'ом, - информация к размышлению.


Время: 12:35.

Время: 12:35.
© OSzone.net 2001-