Skip to Content

IT nieuczesane.
category

Category: DevOps/Scripting

skrypty, programy, command line i inne

regexp – wyrażenia regularne na prostym przykładzie

odkąd poświęciłem kilka godzin na przegryzienie się przez regexpy zakochałem się w tym wynalzq. możliwość matematycznej reprezentacji zapisu słownego – taki revers języków formalnych – to potężna rzecz.

teraz też się przydało. zadanko: jak z sieczki generowanej przez net view wyciągnąć dyski i literki tak, żeby łatwo było potem je obrabiać?

set re = new RegExp
re.pattern="^([a-zA-Z]:) (\\(?:[a-zA-Z0-9.]+\?)+)"
re.ignoreCase=true

to najważniejsza część całego rozwiązania – regexp definiujący zapis typu “X: \serverjakassciezka a potem cokolwiek”. to “cokolwiek” to dopisywaliśmy jako komentarz do pliq, bo nie przywidywaliśmy, że będzie potrzeba późniejszej modyfikacji/sczytywania. geniusz regexpa polega m.in. na tym, że kiedy coś znajdzie, łatwo to wyciągnąć. wyjaśnienie:

^([a-zA-Z]:)[spacja](\\(?:[a-zA-Z0-9.]+\?)+) – każdy znak ma znaczenie:

  • ^ [dash] – oznacza początek linii. jeśli komentarze dawalibyśmy również na początq – wystarczy usunąć
  • () [nawiasy okrągłe]- oznaczają, że to co będzie pasowało do wyrażenia, zostanie zwrócone jako zmienna, z którą można coś później zrobić. w tym przykładzie będzie to literka dysku z dwukropkiem, która będzie przechowywana – dzięki temu mogę to potem wypisać ją lub przerobić jak chcę [np. zamienić na inną]
  • [] [nawiasy kwadratowe] – oznaczają że chodzi o znak z określonego zakresu. tutaj zakresem jest…
  • a-zA-Z – czyli dowolna litera mała lub duża z zakresu a-z
  • : [dwukropek]– po prostu znak. w sumie całe wyrażenie oznacza dowolny ciąg typu “a:”, “M:” itepe
  • [spacja] – podobnie jak w przypadq dwukropka – wszystko co nie jest poprzedzone znakiem specjalnym jest po prostu tym, czym jest – znakiem. a więc spacja to spacja – ta “[spacja]” z przykaładu
  • () – znów nawias, który oznacza, że będzie zwrócona kolejna zmienna [aka $2] – jak się z nich korzysta będzie później
  • \\ [4 backslashe] – backslash to znak specjalny, który eliminuje specjalność znaków specjalnych (; jeśli np. “+” jest znakiem specjalnym ale chodzi nam o znak a nie o jego funkcję, to trzeba poprzedzić go backslashem “+” – i nie będzie interpretowany. znakiem specjalnym jest również backslash, a więc 4 bcks oznacza ciąg “\”
  • (?:) [pytajnik i dwukropek w nawiasach okrągłych] – potem są znów nawiasy, ale tym razem od razu po nawiasie jest pytajnik i dwukropek. zmiennych zwracanych z regexpa może być 9. przy skomplikowanych dopasowaniach może się okazać, że po prostu chcemy coś zgrupować [np,. po to, żeby powiedzieć, że dany ciąg ma wystąpić X razy] ale nie interesuje nas wynik -  nie będzie przydatny do późniejszej obróbki [ma wyłącznie charakter dopasowania]. wtedy dodaje się “?:” oznaczające “nie zapamiętuj tego dopasowania”
  • [a-zA-Z0-9.]+ – część w nawiasie oznacza dowolny znak z zakresu a-z lub A-Z lub 0-9 lub kropkę. plusik na końcu oznacza od 1 do więcej powtórzeń a więc przykładami dopasowania byłyby “aaa”, “10.20.30”, “asd.kjs.d00.00”
  • \? [2backslashe pytajnik] – jak widać z wcześniejszego przykładu, tak i tutaj znak sterujący jest na końcu – tak to jakoś właśnie w regexpach jest. pytajnik oznacza zero lub jedno wystąpienie tego, co stoi przed nim. a przed nim są 2 backslashe, co oznacza ciąg “” który może być albo nie. a to dla tego że w ścieżce dysq jest: “\server12share” – co odpowiada regexpowi, który można by przeczytać “dwa slashe, potem jedno lub więcej wystąpień ciągu składającego się ze ze znaków alfabetu, cyfr lub kropek, po którym jest lub nie pojedyńczy slash”. no tak jest – jedno wystąpienie “server12” i drugie “share”.

teraz jak to wykorzystać w kodzie:

      set file=fso.OpenTextFile(file) 
      fileBody=split(file.ReadAll,VBCrLf)
      for each line in fileBody
        if re.test(line) then 
         set matches = re.execute(line)
'          for each match in matches
'            wscript.echo match.value
'          next
' same-same but different (: 
          wscript.echo matches(0).submatches(0)&" "&matches(0).submatches(1)
        end if
      next 

zmienna ‘file’ to gdzieś tam zdefiniowana nazwa pliq – nieważne. generalnie otwierany jest plik, powstały przy pomocy ‚net view >> somefile.log’, wczytywany do tablicy, w której kolejny wiersz to linia pliq. no i teraz zaczyna się wykorzystanie wyrażeń regularnych.

  • re.test(line) zwraca true/false – czyli czy znalazł dopasowanie czy nie. a więc jeśli linia zaczyna się ciągiem typu “x: \servershare” to o to chodziło. jak nie – olej.
  • set matches = re.execute(line) – sam test niewiele daje. dla tego tworzony jest obiekt, do którego przypisywany jest wynik [kolekcja] z faktycznego ‘uruchomienia’ wyrażenia – trochę to redundantne bo niby sam test to już zrobił, ale trochę konieczne – to takie zabezpieczenie w stylu ochroną przed dzieleniem przez zero. można nie robić testu i po prostu wykonać execute i zobaczyć co zwraca matches.count – czyli ile jest trafień. do wyboru, do koloru
  • potem jest kilka wykomentowanych linijek, a to dla tego, że dalsza część kodu robi to samo, tylko bardziej uniwersalnie. ale zostawiłem, ponieważ to dwa sposoby wyświetlenia wyników – pierwszy ogólny:
  • for each match in matches – jak pisałem, zwracana jest kolekcja, a więc ‘dla każdego dopasowania w kolekcji’
  • wscript.echo match.value –  match.value to wartość dopasowania – całego – i dla tego ciężko coś z tym zrobić później.
  • wscript.echo matches(0).submatches(0)&" "&matches(0).submatches(1) – w tym konkretnym przypadq wynik na ekranie będzie dokładnie taki sam, ale możliwości są zupełnie inne. wyjaśnia się też tajemnica ‘zapamiętywanych zmiennych’ – które wyszuqje się za pomocą nawiasów (). w przykładzie w nawiasach były dwa dopasowania – litera dysku z dwukropkiem oraz sama ścieżka. i dokładnie to jest wypisywane – matches(0), ponieważ to pierwszy element kolekcji [i w tym przypadq jedyny – dokładnie ten, który był w powyżej wypisany jako całość] – a potem występuje ‘submatches(X)’ – co jest adekwatne do $1, $2 etc – oznacza numer ‘zapamiętaj zmiennej’ liczony od zera. a więc submatches(0) to np. ‘M:’ a submatches(1) to np. “\servershare” dzięki temu można je wykorzystać w dowolnym momencie – choćby zamienić ich kolejność, wykonać operację na jednym z nich [np. uppercase]

regexpy mają wiele fajnych zastosowań – wszędzie tam, gdzie trzebaby w kodzie zrobić pierdylion if’ów, case’ów i innych wynalazków – które średnio się nadają do operacji na niezbyt przewidywalnych stringach. dzięki wyrażeniom regularnym można zdefiniować to w lu
dzkim języq.. chociaż wygląda totalnie nieludzko i mało podobnie do języka (; przykładem zastosowania są zasady normalizacji numerów telefonów – czy ktoś wpisze +48 czy 22 czy +4822 czy tylko numer telefonu, a może potem jest jakiś numer wewnętrzny? a jak firma jest w kilq lokalizacjach to prefixy będą inne, a czy numer telefonu ktoś wpisał jako 345-67-89 czy może 3456789 a może ze spacjami?… i tak dalej. a na wyjściu musi zawsze być znormalizowany numer telefonu dla danej lokalizacji. zapisuje się to bardzo prostymi wyrażeniami regularnymi w stylu “^((00|+)48)?(d{3}.?d{2}.?d{2})(d{4})?” q: pisząc to mam na myśli OCS, i tak na prawdę to wygląda tam dużo prościej.

reasumując – niewiarygodnie wygodne narzędzie, które może nie przydaje się na co dzień ale kiedy jest dla niego zastosowanie, robienie tego innymi metodami jest strzałem w kolana.

linki

ps. czemu nie w powerShell? bo siedzę tam, gdzie się teren jeszcze renderuje, i musiałem skleić coś na szybko. ale uh… trzeba będzie usiąść i do poweshella

n.

powershell grep

w PS braqje czegoś aka grep. po krótkich poszukiwaniach można znaleźć polecenie ‘Select-String –pattern “czego szukam” ‘ ale po krótkich testach okazuje się, że to się zachowuje trochę niedeterministycznie… znaczy się… trzeba mieć pewność, że to, co zwraca inny cmdlet to string. wystarczy kilka doświadczeń typu:

  • get-childitem | Select-String –pattern “win” – działa ok i wypisze np. “Windows”
  • get-help | Select-String –pattern “syn” – już nie zadziała wedle oczekiwań
  • get-help get-childitem | Select-String –pattern “syn” – zadziała totalnie nie wedle oczekiwań

taki to dziwny zwierz. zaufać mu w każdym razie dość trudno w obecnej postaci. dla tego polecam przypomnieć sobie taki systemowy util, który polecam, bo działa deterministycznie:

PS C:> findstr /?
Searches for strings in files.

FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/P] [/F:file]
        [/C:string] [/G:file] [/D:dir list] [/A:color attributes] [/OFF[LINE]]
        strings [[drive:][path]filename[ ...]]

n.

Backup SVN (Windows + Apache)

Jako, że nie da się backupować bezpośrednio repozytorii SVN będących on-line, trzeba było napisać prosty skrypt, który najpierw zrobi ich hotcopy a dopiero potem backup na zadaną lokalizację sieciową. Zamiast robienia backup set i używania ntbackup można spakować cały folder docelowy i przegrać go zwykłym xcopy, w sumie wyjdzie na to samo a pewnie będzie szybciej i prościej do odzyskiwania.

Środowisko:
Windows Server 2003
Apache 2.2 z modułem SVN

' SVNbackup.vbs
' Backups all SVN repositories from selected directory + Apache config
' Author Kuba Siatkowski http://w-files.pl/author/kfaz
' ver 1.0.1


optionexplicit Const FOR_READING = 1 Dim strReposFolder, colReposFolders, strBackupFolder, colBackupFolders, strBackupLocation, strApacheLocDim objFSO,WshShell, objReposFolder, objBackupFolder, objSubFolder, objSubBackupFolder, strBackupset, fileBackupset

strReposFolder = "C:RepositorySVN"                                 ' place where all SVN repos are
strBackupFolder = "C:backup"                                      ' temp folder for local backups
strBackupLocation = "\backupserverbackupsharebackupname.bkf"     ' place for backups
strApacheLoc = “C:Apache” ‘apache directory (SVN configs, plug-ins etc)
strBackupset = strBackupFolder&“backupset.bks”


Set objFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objReposFolder = objFSO.GetFolder(strReposFolder)
Set colReposFolders = objReposFolder.SubFoldersSet
objBackupFolder = objFSO.GetFolder(strBackupFolder)
Set colBackupFolders = objBackupFolder.SubFoldersSet
fileBackupset = objFSO.CreateTextFile(strBackupset, True)

'delete old backups from temp folder
For Each objSubBackupFolder In colBackupFolders


objSubBackupFolder.Delete True

Next

‘hotcopy all repos from reposdir and create backupset
For Each objSubFolder In colReposFolders

WshShell.run "svnadmin.exe hotcopy "&strReposFolder&""&objSubFolder.Name&" "&strBackupFolder&objSubFolder.Name, 1, true
fileBackupset.WriteLine ""&strBackupFolder&objSubFolder.Name&""

Next

'add Apache to backupset
fileBackupset.WriteLine ""&strApacheLoc fileBackupset.close ‘do the backup
WshShell.run "ntbackup.exe backup @"&strBackupset& " /n ""SVN Repos “&Now&""" /v:yes /r:no /rs:no /hc:off /m normal /j ""SvnBackup""/l:s /f "&strBackupLocation, , true

Czy programowanie może być zabawą?

takie oto pytanie zawitało dzisiaj w moim RSS readerze, zadane przez GT – przepraszam Cię Grzesiu, że nie w komentarzach tylko tak tutaj – ale pytanie ciekawe, a odpowiedź zbyt długa, żeby ją wklepywać jako comment – a ping backa powinieneś dostać [jeśli masz włączonego]. nie traktuj tego więc jako atak – to czysta polemika (:

“A kto pamięta LOGO? Proste to było do bólu, ale uczyło myślenia.”

oj pamiętam ci ja logo, pamiętam – uczyłem się go na bosmanach 8. założeniem logo była edukacja i na początq lat 9o’  miało to sens. kilka lat temu [ok 4-5] miałem nieprzyjemność uczenia logo – takiego nowego, z innym edytorem, niby-obiektowego etc. mając porównanie czasów ‘wtedy’ oraz ‘dziś’ mogę śmiało powiedzieć – LOGO TO SYF. język nieprzemyślany, gdzie na siłę wtrącono część obiektowości, pozostawiając w wielu miejscach podejście strukturalne, totalnie zwalony edytor, który wręcz zmusza do zrobienia bałaganu w kodzie, ciężko cokolwiek znaleźć – po prostu masakra. jedyne czego można po logo oczekiwać to nauczenia się totalnie złych manier programowania, niespójności i raczej się można zrazić niż nauczyć. do dziś na murach można spotkać napisy ‘punk not dead’ a nawet czasem odbędzie się jakiś koncert – gdzie 8o% ludzi jest powyżej 4otki. z logo jest podobnie – należy pochylić czoło nad kawałkiem historii i zapomnieć.

“W systemie DOS, podobnie jak w ośmiobitowcach (nie wnikam czy było to Atari, Commodore, Spectrum czy jeszcze coś innego) proste środowisko programistyczne było dostępne od ręki. A teraz?”

a teraz od wieków w windzie jest WSH, od niedawna powershell, w linuxach bash… oj bez GUI? no to TCL … ale po co w ogóle szukać po jakiejś niszy? czemu nie Java lub .NET – pierwsze prawdziwie języki obiektowe? być może ponieważ:

“Pomijam już to, że środowiska programistyczne zazwyczaj są olbrzymimi pakietami oprogramowania, które zachowują się nieraz tak, jakby były samodzielnymi systemami.”
oraz
Pomijając kwestie środowiska, programowanie w XXI wieku nie jest tak proste jak kiedyś. Dawniej dało się napisać program mieszczący się w jednym pliku, bez tony #include i innych Using.

nie prawda. do napisania ‘hello world’ potrzebujesz dokładnie tylko samo kodu – no ok. z jednego includa trzeba dodać. i bardzo dobrze. ale jeśli chcesz coś narysować, napisać lub skorzystać np z sieci – kiedyś musiałeś napisać toooooonę kodu – teraz dołączasz bibliotekę, która i tak działa o niebo lepiej niż większość by to sama zrobiła. i jest przenośne. zamiast uczyć się ‘jak coś działa’ [np. przebijanie się przez RFC od TCP/IP] sqpiasz się na logice – w końcu developer nie musi być architektem. równie dobrze można powiedzieć, że najlepszy był assembler. po co mam pisać algorytm na rysowanie koła, skoro mogę po prostu napisać rysujOkrag(10) q:
co do kompilatora – nie trzeba instalować visual studio – może owszem, microsoft ma taką politykę, że .net kojarzy się z VS, ale przecież wystarczy dobry edytor z podkreślaniem składni [np. pspad] – zarówno do javy jak i .neta i zainstalowany framework/VM. nie jestem ‘na bieżąco’ ale są małe środowiska do obu tych języków – po szybkim googlaniu np. tutaj. małe, szybkie, do pierwszych zabaw wystarczą – wcale nie trzeba SQL ani pierdyliona dodatków.

Tylko, czy przypadkiem nie stało się tak, że zginęła w tym radość z napisania czegoś, co działa? Czy dzisiaj dziesięciolatek ma szansę siąść i napisać kilka albo kilkadziesiąt linii kodu, które zapytają o imię i wyświetlą okienko, w którym to imię zostanie wstawione w komunikat "Jasio umie programować!"?

imho – nie. co więcej – ma szansę to zrobić bez problemu, ponieważ to nie jest na tym etapie kwestia języka tylko nauczyciela oraz kompilatora. taka aplikacja to w javie tyle samo kodu w VB – a jeśli jest go więcej wizualnie, to i tak ‘sprytny edytor’ doda wszystko co potrzebne na początek – a co to oznacza można wytłumaczyć później.
różnica polega jednak na tym, że jak ktoś się zacznie uczyć języków strukturalnych, a już nie-daj-wielki-informatyku takich archaizmów jak BASIC, to potem będzie musiał się na nowo uczyć obiektowych. wiem – bo sam przez to przeszedłem i przełamanie sposobu myślenia jest dość bolesne. developerem nie zostałem [czego trochę żałuję, ale tak się potoczyło], ale miałem okazję kombinować w różnych wynalazkach – logo, basic, pascal, c, c++, java, .net, php, vbs+hta, sql, vba, fortran, c-MPI, shellowe cmd, bash itd – i po wszystkich przejściach, zakochałem się w obiektowości. dla tego z resztą tak dobrze gada mi się z AD a tak bardzo nie znoszę poronionego SQL. imho warto zainwestować czas od razu w coś, co będzie przyszłościowe, zamiast babrać się w oldschoolu. nie twierdzę, że to nie ma wartości edukacyjnych, ale to ślepa uliczka i pewne zderzenie z rzeczywistością jeśli ktoś w tym kierunq będzie podążał.

“Mówiąc w największym skrócie: Jestem za powrotem BASICa do łask!”

w-życiu-never! (;

jeśli chodzi o 1o latków – ale nie tylko – to polecam grę CeeBot – imho do osób, które chcą efekty zobaczyć najszybciej – docieranie poprzez fabułę jest najefektywniejszy – i nie tylko zobaczymy ‘jaś jest programistą’ ale w ciągu kilq chwil można sterować własnym robotem! Chciałem nawet robić z tego zajęcia, ale licencja edu była za droga na moją kieszeń, a uczelnia nie chciała wydawać ):

n.

Przenoszenie nieaktywnych kont do innego OU

Trzeba było znaleźć wszystkich użytkowników, którzy nie logowali się od dłuższego czasu i przenieść ich do innego OU.
Problemy jakie się pojawiły to wartość atrybutu LastLogonTimeStamp, która jest specyficzna (liczba milisekund od epoki) i przenoszenie obiektów w AD. O ile pierwsze było proste do wygooglania o tyle z drugim strasznie ludzie kombinują, piszą miliony linii kodu i generalnie żadne z tych rozwiązań mi się nie podobało. Chwila samodzielnego kombinowania, trochę rzeźby i olśnienie w postaci, że PowerShell to przecież… shell :) i że działają w nim komendy commandlinowe takie jak np. dsmove :)

Poniżej skrypt, który znajduje wszystkich w danym OU , którzy nie logowali się od 14 miesięcy i przenosi ich od OU inactive. Minimalne wymagania: domena w trybie “Windows Server 2003”

Ustawianie msSFU30GidNumber dla wszystkich grup w domenie

Linuxy potrzebują parametru msSFU30GidNumber żeby widziały grupy z Active Directory. Do tej pory pojedyńcze MsSFUGidy robiliśmy ręcznie z ADSIEdit, jednak kiedy przyszło ponad sto nowych grup to trzeba było to jakoś oskryptować.

Skrypt poniżej:

  1. znajduje maksymalny MsSFUGid w domenie
  2. wszystkim grupom, które nie mają msSFUGID przypisuje kolejne numery 

Jego wadą jest to, że dodaje Gidy wszystkim grupom ale to można zmienić np. poprzez ustawienie odpowiedniego roota przed drugą pętla.

$Root = New-Object DirectoryServices.DirectoryEntry $strROOT
$Searcher = New-Object DirectoryServices.DirectorySearcher
$Searcher.SearchRoot = $root
$searcher.Filter =  "(&(objectClass=Group))";
$numer = 0;
$gid ;
$groups = $searcher.findAll();
foreach ($group in $groups)
{
   $de = New-Object DirectoryServices.DirectoryEntry $group.Path;
   $gid = [int]$de.msSFU30GidNumber.ToString();
#  write-host $gid ";" -NoNewLine;
#  write-host $de.name;
   if ($numer -lt $gid )
   {
     $numer = $gid;
#    $numer;
   }
}
$numer++;

foreach ($group in $groups)
{
  $de = New-Object DirectoryServices.DirectoryEntry $group.Path;
  $gid = [int]$de.msSFU30GidNumber.ToString();
  if ($gid -eq 0)
  {
    $de.msSFU30GidNumber = $numer;
    $de.SetInfo();
    write-host $numer ";" -NoNewLine;
    write-host $de.name;
    $numer++;
  }
}

Pozwalanie użytkownikom na uruchamianie/zatrzymywanie serwisów

Mamy na stacji zainstalowanego Apacha, Network Inspectora czy Flash Server i nie chcemy żeby chodziły one przez cały czas i bezsensownie zżerały nam zasoby. Chcemy pozwolić użytkownikowi na uruchamianie/zatrzymywanie serwisów i nie nadawać mu zbędnych uprawnień. Najprościej jest to zrobić ustawiając z poziomu domeny odpowiednią polisę która ustawi odpowiednie ACL na dany serwis (tak serwisy też mają ACL :o ).
Co jednak zrobić w momencie gdy komputer nie jest w domenie? Zawsze wydawało mi się, że wszystko da się ustawić w Local Security Policy. Windows + R wpisuję secpol.msc (albo gpedit.msc, jak kto woli ;) ) enter i nie ma serwisów :-o . Wszystko wskazuje na to, że nie da rady tego ustawić lokalnie jednak z pomocą przychodzi Security Configuraration and Analysis (dla nieświadomych start -> run -> mmc -> ctrl+m -> add -> Security Configuraration and Analysis ). Dodaję nową bazę, importuję template (dla bezpieczeństwa polecam setup security.inf), analizuję komputer, po czym kiedy już pokaże mi się drzewko wchodzę w System Services wybieram interesujący mnie serwis i ustawiam mu ACL’ki :) .
Ciekawe czemu jest to wycięte z interfejsu w secpol.msc? Po co wycieli coś co i tak da się ustawić? bez sensu…

Po tem jeszcze warto dać użytkownikom narzędzie pozwalające na wygodnie uruchamianie/zatrzymywanie serwisów. Może to być prosty batch wyglądający mniej więcej tak:
NET START "Nazwa serwisu"
albo tak:
NET STOP "Nazwa serwisu"

A gdybyśmy chcieli pisać to w Visual Basicu (np. po to żeby sprawdzać coś zanim nasz serwis wstanie, zrobić ładny interface graficzny itp. itd.) to przyda się ten kawałek kodu:

' Uruchom zatrzymaj serwis
option explicit
dim queryString
dim Service, ServiceSet

queryString = "select * from Win32_Service where Name=’Nazwa serwisu’ and State=’Stopped’"
Set ServiceSet = GetObject("winmgmts://.").ExecQuery(queryString)

if ServiceSet.Count <> 0 then
WScript.echo “Uruchamiam serwis”
for each Service in ServiceSet
Service.StartService()
next
else
WScript.echo “Jesteś kretynem, serwis już działa”
end if

Jakie aliasy stworzyć w shellu?

Poniższe pokazuje listę poleceń wraz z ich ilością wywolanych np. w bash albo ksh.

Jeśli jakieś rozbudowane polecenie wywołujesz często, może warto zrobić aliasa dla niego:

history|awk '{print $2}'|awk 'BEGIN {FS="|"} {print $1}'|sort|uniq -c|sort

MUI – script it

Ostatnio siedzę i bawię się windowsowym Multilingual User Interface. Posiłkując się tym oto artykułem zintegrowałem MUI z instalką na RISie. Ale tu pojawił się problem – jak niezbyt technicznym ludziom pokazać sposób zmiany języka? Tutorial? Nieeeeeee. Za dużo pracy ;) Idąc za radą NeXoRa „If it moves – script it” udało mi się z Kfaz’a pomocą spłodzić coś takiego:

Piczek.vbs

jap.reg

Ogólnie idea jest prosta. Podmień wpisy w rejestrze (znalezienie ich trwa krótką chwilę), zabij explorera i uruchom go w kontekście nowego UI. Co do kodów języków, to są one dostępne tutaj.

dla programistów

siedzę nad c# zdobywając tytuł ‚master of strings’ bo muszę pisać coś w stylu dziwnego parsera. nauczyłem się regexpów, i dziwnych wynalzków do konwertowania.

i tak a propos stringów

tutaj jest jeszcze kilka fajnych od bartosza:
http://stackoverflow.com/questions/84556/whats-your-favorite-programmer-cartoon

a teraz mała dziwnostka:
oczywiście dotarłem do kłamstwa, nad którym musiałem się sporo nabiedzić. funkcji konwertujących jest w pytkę ale oczywiście jak się ma konkretny pomysł to nic nie działa jak powinno. ot taki świetny link pokazujący potęgę konwersji. jest tam taki opisik:

Every object has a method called ToString that returns a string representation of the object. The ToString method can accept a string parameter, which tells the object how to format itself – in the String.Format call, the formatting string is passed after the position, for example, “{0:##}”


no i qpa. problem: skonwertować liczbę zmiennoprzecinkową tak, aby była wyrównana do prawej, z dokładnością do dwóch znaków po przecinq w zapisie amerykańskim [‚.’ oddziela część dziesiętną]. no więc można byłoby tak:

float flt=-1234,289F;
string out= flt.ToString("{0,15:0.00}");

co oczywiście nie zadziałało. taka konwersja działa w ogóle bardzo dziwnie – wszystkie znaczki { , : etc – traktowane są jak część liczby i wychodzi z tego:

-{1 2315:4,29}

a więc trochę jakby nie to. ponieważ występuje w zdaniu ‚formatuje sam siebię’ a więc można pominąć {0} bo wiadomo, że to o niego chodzi. Ciekawie traktowany jest minus – zupełnie jakby liczba składała się z liczby i z minusa:

string out=flt.ToString(" 0.00");

co powinno pokazać liczbę przesuniętą o klika spacji w prawo. wynik:

- 1234,29

wygląda na to, że ToString z przeciążenia na liczbie nie przyjmuje parametrów formatowania. finalnie trzeba było skomplikować:

string out=string.Format("{0,15}",flt.ToString("0.00",new System.Globalization.ClutureInfo("en-US")));

ufff.. niuanse językowe…