Quick fix - schematron - schematron

I wrote a quickfix to insert a space between digit and string for example: 15MHz,20Hz
Schematron
<sch:pattern>
<sch:title>quick-fix</sch:title>
<sch:rule context="//text()">
<sch:report
test="matches(.,'(\d+)MHz') or matches(.,'(\d+)Hz')"
sqf:fix="groupfix" role="warning">Insert a space</sch:report>
<sqf:group id="groupfix">
<sqf:fix id="MHz-fix" use-when="contains(current(), 'MHz')">
<sqf:description>
<sqf:title>Insert space before MHz
</sqf:title>
</sqf:description>
<sqf:replace>
<xsl:analyze-string select="." regex="(\d+)MHz">
<xsl:matching-substring><xsl:value-of select="regex-group(1)"
/><xsl:value-of select="' MHz'"
/></xsl:matching-substring>
<xsl:non-matching-substring><xsl:value-of select="."
/></xsl:non-matching-substring>
</xsl:analyze-string>
</sqf:replace>
</sqf:fix>
<sqf:fix id="Hz-fix" use-when="contains(current(), 'Hz')">
<sqf:description>
<sqf:title>Insert space before Hz
</sqf:title>
</sqf:description>
<sqf:replace>
<xsl:analyze-string select="." regex="(\d+)Hz">
<xsl:matching-substring><xsl:value-of select="regex-group(1)"
/><xsl:value-of select="' Hz'"
/></xsl:matching-substring>
<xsl:non-matching-substring><xsl:value-of select="."
/></xsl:non-matching-substring>
</xsl:analyze-string>
</sqf:replace>
</sqf:fix>
</sqf:group>
</sch:rule>
</sch:pattern>
xml
<topic>
<p>15MHz</p>
</topic>
I am able to insert the space before MHz but the quick fix displays two options "Insert space before MHz" and "Insert space before Hz". I want only "Insert space before MHz" to be displayed.
Please help. Thanks

In stead of this:
<sqf:fix id="Hz-fix" use-when="contains(current(), 'Hz')">
do this:
<sqf:fix id="Hz-fix" use-when="matches(current(), '(\d+)Hz')">
Use in use-when also the matches function which checks for the given pattern.
Optional:
you can replace current() with . to save code.
In Oxygen you can use <sqf:stringReplace regex="(\d+)Hz" select="'$1 Hz'"/> instead of the complex <xsl:analyze-string>.

Related

how do I filter my values using an array?

I am trying to sift through some free text answers on geographical locations. As one of the steps, I want to check if the answer is any of the 290 municipalities in my country. As 290 entries would make my code cumbersome/hard to read I try saving them in an array, like below:
Data resorTEST;
keep R_res_ort_namn R_res_ort_txt R_kom_lan R_kommun;
set resor1TEST resor2TEST resor3TEST;
R_res_ort_namn=strip(lowcase(R_res_ort_namn));
R_res_ort_txt=strip(lowcase(R_res_ort_txt));
R_kom_lan=strip(lowcase(R_kom_lan));
array kommuner{290} $ ("upplands väsby" "vallentuna" "österåker" "värmdö"
"järfälla" "ekerö" "huddinge" "botkyrka" "salem"
"haninge" "tyresö" "upplands-bro" "nykvarn" "täby"
"danderyd" "sollentuna" "stockholm" "södertälje" "nacka" "sundbyberg"
"solna" "lidingö" "vaxholm" "norrtälje" "sigtuna" "nynäshamn"
"håbo" "älvkarleby" "knivsta" "heby" "tierp" "uppsala"
"enköping" "östhammar" "vingåker" "gnesta" "nyköping" "oxelösund" "flen"
"katrineholm" "eskilstuna" "strängnäs" "trosa" "ödeshög" "ydre"
"kinda" "boxholm" "åtvidaberg" "finspång" "valdemarsvik" "linköping"
"norrköping" "söderköping" "motala" "vadstena" "mjölby" "aneby"
"gnosjö" "mullsjö" "habo" "gislaved" "vaggeryd" "jönköping"
"nässjö" "värnamo" "sävsjö" "vetlanda" "eksjö" "tranås"
"uppvidinge" "lessebo" "tingsryd" "alvesta" "älmhult" "markaryd"
"växjö" "ljungby" "högsby" "torsås" "mörbylånga" "hultsfred"
"mönsterås" "emmaboda" "kalmar" "nybro" "oskarshamn" "västervik"
"vimmerby" "borgholm" "gotland" "olofström" "karlskrona" "ronneby"
"karlshamn" "sölvesborg" "svalöv" "staffanstorp" "burlöv" "vellinge"
"östra göinge" "örkelljunga" "bjuv" "kävlinge" "lomma" "svedala"
"skurup" "sjöbo" "hörby" "höör" "tomelilla" "bromölla"
"osby" "perstorp" "klippan" "åstorp" "båstad" "malmö"
"lund" "landskrona" "helsingborg" "höganäs" "eslöv" "ystad"
"trelleborg" "kristianstad" "simrishamn" "ängelholm" "hässleholm" "hylte"
"halmstad" "laholm" "falkenberg" "varberg" "kungsbacka" "härryda"
"partille" "öckerö" "stenungsund" "tjörn" "orust" "sotenäs"
"munkedal" "tanum" "dals-ed" "färgelanda" "ale" "lerum"
"vårgårda" "bollebygd" "grästorp" "essunga" "karlsborg" "gullspång"
"tranemo" "bengtsfors" "mellerud" "lilla edet" "mark" "svenljunga"
"herrljunga" "vara" "götene" "tibro" "töreboda" "göteborg"
"mölndal" "kungälv" "lysekil" "uddevalla" "strömstad" "vänersborg"
"trollhättan" "alingsås" "borås" "ulricehamn" "åmål" "mariestad"
"lidköping" "skara" "skövde" "hjo" "tidaholm" "falköping"
"kil" "eda" "torsby" "storfors" "hammarö" "munkfors"
"forshaga" "grums" "årjäng" "sunne" "karlstad" "kristinehamn"
"filipstad" "hagfors" "arvika" "säffle" "lekeberg" "laxå"
"hallsberg" "degerfors" "hällefors" "ljusnarsberg" "örebro" "kumla"
"askersund" "karlskoga" "nora" "lindesberg" "skinnskatteberg" "surahammar"
"kungsör" "hallstahammar" "norberg" "västerås" "sala" "fagersta"
"köping" "arboga" "vansbro" "malung-sälen" "gagnef" "leksand"
"rättvik" "orsa" "älvdalen" "smedjebacken" "mora" "falun"
"borlänge" "säter" "hedemora" "avesta" "ludvika" "ockelbo"
"hofors" "ovanåker" "nordanstig" "ljusdal" "gävle" "sandviken"
"söderhamn" "bollnäs" "hudiksvall" "ånge" "timrå" "härnösand"
"sundsvall" "kramfors" "sollefteå" "örnsköldsvik" "ragunda" "bräcke"
"krokom" "strömsund" "åre" "berg" "härjedalen" "östersund"
"nordmaling" "bjurholm" "vindeln" "robertsfors" "norsjö" "malå"
"storuman" "sorsele" "dorotea" "vännäs" "vilhelmina" "åsele"
"umeå" "lycksele" "skellefteå" "arvidsjaur" "arjeplog" "jokkmokk"
"överkalix" "kalix" "övertorneå" "pajala" "gällivare" "älvsbyn"
"luleå" "piteå" "boden" "haparanda" "kiruna");
/*if not missing(R_res_ort_namn) then R_kommun=prxchange("s/^.*-(.* kommun)/$1/",1,R_res_ort_namn);
else if prxmatch("/^.*([a-zA-Z]*? kommun).*$/",R_res_ort_txt) then R_kommun=prxchange("s/^.*?([a-zA-Z]*? kommun).*$/$1/",-1,R_res_ort_txt);
else if prxmatch("/^.*([a-zA-Z]*? kommun).*$/",R_kom_lan) then R_kommun=prxchange("s/^.*?([a-zA-Z]*? kommun).*$/$1/",-1,R_kom_lan);
else */if R_res_ort_txt in kommuner then R_kommun=R_res_ort_txt;
run;
However, for some reason this does not seem to work for all of the municipalities. The municipality of "uppsala" works for instance, but not the municipality of "ängelholm".
I have tried stripping the variables of whitespace and converting everything to lowercase. What am I doing wrong?
Additional info:
For some reason it does work flawlessly if I skip the array and just copy-paste the exact same list of municipality names into a parenthesis following the in-operator. I would however need to repeat this step 5-6 times and this solution would make my code quite cumbersome.
You are defining the ARRAY
Array kommuner{290} $
with character length 8. See what happens when you fix that.

Convert string to XML format in C language

I have a question, is there an algorithm that converts the corresponding logical expression as a string to xml format?
For example:
I am loading logical expressions as a string from the input file:
(X&Y)|Z
And now to convert it into xml format, to get something like this in a new file:
<expression>
<or>
<operand>Z</operand>
<and>
<operand>X</operand>
<operand>Y</operand>
</and>
</or>
</expression>
Thanks in advance!
(Responding to the xml tag.)
Perhaps you can make use of invisible-xml (ixml),
the SO Info
tab lists several resources.
With a grammar such as
ixml version "1.0".
expression: expr.
-expr: operand; and; or; not.
and: expr, -"&", expr.
or: expr, -"|", expr.
not: -"!", operand.
-operand: id; -"(", expr, -")".
id: letter.
-letter: ["A"-"Z"].
the ixml processor coffeepot
java -jar '/usr/local/share/java/coffeepot-1.99.11.jar' \
--grammar:expr-bool.ixml --pretty-print '(X&Y)|Z'
produces the following output:
<expression>
<or>
<and>
<id>X</id>
<id>Y</id>
</and>
<id>Z</id>
</or>
</expression>
With the input (X&Y)|Z&!(A|B) coffeepot (by default) outputs the
first of (in this case 2) possible parses and emits the root element as
<expression xmlns:ixml="http://invisiblexml.org/NS" ixml:state="ambiguous">
to point out the ambiguity.
If parsing fails the output could be something like:
<fail xmlns:ixml="http://invisiblexml.org/NS" ixml:state="failed">
<line>1</line>
<column>14</column>
<pos>14</pos>
<end-of-input>true</end-of-input>
<permitted>['A'-'Z']</permitted>
</fail>

Need to write a regex to parse the command

Need to write a regex to get 3 groups from strings-
<whatever text including new lines optional -group 1>/command <text until \n or </p> is encountered- group 2><whatever text including new lines optional -group 3>
what I tried is-
Pattern pattern1 = Pattern.compile('(.*?)[/]command (.*?)\n?(.*?)');
It should give the following output for string-
some\nthing/command cmdtext/nasdfjaklsdjf\nfgskdlkfg\ndgsdfgsdfgsdfg
group 1 - some\nthing
group 2 - cmdtext
group 3 - asdfjaklsdjf\nfgskdlkfg\ndgsdfgsdfgsdfg
What I am not getting is how to get the occurrence of </p> and .* is not considering the group. Although this is working for me-
String a = '\na\na\n\n\n\n\n\naaa';
Pattern pattern2 = Pattern.compile('\n(?s:.)*');
Matcher mchr = GiphyPattern.matcher(a);
system.assert (mchr.matches());
This regular expression should match what you need:
'([\\s\\S]*)/command (.*?)(?:\n|</p>)([\\s\\S]*)'
You cannot match \n with .* So I am using \\s\\S instead (which is actually \s\S but with Apex escaped backslashes).

StAX Parser : Duplicated Node name and specific comments

I'm try to parse xml file with StAX parser but I face two problems:
First: Two nodes have the same name
Second: read the exactly comment before the values
<database>
<!-- 2015-03-10 01:29:00 EET / 130 --> <row><v> 2.74 </v><v> 1.63 </v></row>
<!-- 2015-03-10 01:30:00 EET / 170 --> <row><v> 5.33 </v><v> 1.68 </v></row>
<!-- 2015-03-10 01:31:00 EET / 180 --> <row><v> 7.62 </v><v> 1.83 </v></row>
<database>
I want to collect the data like that:
Date:2015-03-10 01:29:00
V1: 2.74
V2:1.63
I was using Dom parser before and it was so easy to deal with dublicate node name and comments unfortunately I have to use StAX now and I don't know how to solve those problems :(
The first issue: two nodes have the same name
<v> 2.74 </v><v> 1.63 </v>
There is no issue with StAX, if you follow the events you will get in order:
startElement ( v )
characters ( 2.74 )
endElement ( v )
startElement ( v )
characters ( 1.63 )
endElement ( v )
So it is up to you to handle minimal of context information in your code to know if it is the first or the second time you are starting a <v> element.
The second issue: read the comments
There is no issue neither, the StAX parsing triggers events for comments as well, you can simply get the comment as String with the API and extract yourself the expected value, for instance:
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader streamReader = inputFactory.createXMLStreamReader(inputStream);
while (streamReader.hasNext()) {
int event = streamReader.next();
if(event == XMLStreamConstants.COMMENT) {
String aDateStringVal = streamReader.getText();
// + extract your date value from the comment string
}
}

Move file to archive if header contains a specific string using vbs

I have a problem processing Holter ECG (medical) files based on headers within. Those are binary datafiles that are approximately 20 MB in size starting with structured header and than the data. What I would like to achive is preferably with vbs script is:
1) To check all files in the current folder and move the processed ones to the archive folder -based on specific string in the header:
After a constant string "User Field #20" comes a 250-400 chars long text string that contains a substring like "Wn:" or "WN:" or "wn:" (with colon). If its there the file is processed and goes to archive.
The two examples hold conclusion strings like:
i)
Analize przeprowadzono w warunkach szpitalnych. Rytm prowadzacy zatokowy z HR sr 70/min ( zakres 45-133/min).
Zarejestrowano 1 SVPB, bez epizodow czestoskurczu. Komorowych zaburzeń rytmu serca nie ma.
PQ i QTc w normie.
WN: zapis prawidłowy bez zaburezń rytmu serca
ii)
Zapis w warunkach szpitalnych. Rytm zatokowy, HR w zakresie 38 /min do 126/min, średnio 66/min; przeciętnie w dzień 58-95/min, w nocy 52-65/min. Nie zarejestrowano SVPB, VPB, pauz>2,5sek.PQ w normie wiekowej. QTc prawidłowe. Dobowy profil rytmu w normie.
Wn: Zapis holterowski bez cech istotnej patologii
Newlines, special and regional chars possible within the string. I cant tell for sure but seems like the conclusions string ends with hex 80 (euro sign).
2) If possible - add log to the script - plain text, semicolon separated (maybe to be uploaded to excel if necessary).
archive_log.txt: Timestamp; Lastname; Firstname; DateRecorded; DateProcessed; ConclusionsLongText (about 250-400 chars).
DateRecorded and DateProcessed based on files date created and last modified.
This is extension of a problem that was solved some time ago. The problem is different, only the files to handle are the same. Use the contents of a file to rename it
You could use the same strategy Ansgar used in the link you referenced. Read the file contents and then you can use InStr() to search for your string:
' Read the entire file into a string...
strContents = objFS.OpenTextFile("file.dat").ReadAll()
' Search for the string "WN:" (case-insensitive)...
intPos = InStr(1, strContents, "WN:", vbTextCompare)
If intPos > 0 Then
' Found
End If
This should find the first "WN:" occurrence within the file. Note that this could be some other occurrence, outside the header, so you could also determine the position of "User Field" and compare that to the position of "WN:". For example:
intPosUser = InStr(1, strContents, "User Field", vbTextCompare)
intPosWN = InStr(1, strContents, "WN:", vbTextCompare)
' "WN:" should be within 400 chars of the first User Field record...
If intPosWN > intPosUser And intPosWN - intPosUser < 400 Then
' Found
End If

Resources