I am getting data in an inbound EDI file and one of the fields has measurements which I need to parse out of a single string. An example of this field is:
11.75x21.25x41.37x
I need to take all the values in front of the first X and push them to a destination field (say length), all the values between the 1st and 2nd X and push those to the destination field "width", and all the data between the 2nd and 3rd x and send that to the destination field "height".
Here's the challenge: can this be done using only functoids, no C# code? It is preferred because managing C# code should the client modify the format of the data between the X's (as they may well do) is easier to maintain if no code needs to be modified, vetted, stored and pushed to the server.
I tried using the string trimming and string exact functoids but it didn't work; there is no fixed number of digits between the X's and I cannot even be guaranteed there will always be decimals--another feature I originally wanted to key on. The only constant will be the X's.
Yes, you can do this using only functoids - but if you artificially stipulate that you not use C# (in a scripting functoid), then you make life much harder and don't solve the problem you think you're solving.
You'd have to use multiple String Find functoids to pick out the various pieces of the field - and this will work only assuming you know the number of xes that can occur ahead of time. Have the first input be the node, and the second input be x for string find, then connect that to a String Extract functoid. To get the second one you'll have to stack the String Find functoids, and life gets ugly. You're effectively trying to build out recursion manually using BizTalk functoids.
The bottom line is: no matter how you achieve this, if the client changes the format of the string you'll have to change the parsing logic to get it out. That logic will be vastly easier to manage by writing a custom functoid (or just an external Assembly method) which, at its core, does this:
public string StringPartAt(string s, string sep, int idx)
{
string[] splits = s.Split(sep[0]);
if (splits.Length > idx)
return splits[idx];
return "";
}
This will be much easier to maintain and understand. You could set that in a Scripting functoid and pass in your node, x, and a zero-based index to get your string out, and just use that for as many times as you need to split things up. You could even add error handling/logging ("Warning: Tried to extract value that was out of range of input" in the EventLog might be appreciated). If you're worried about the Client's facility with C#, you could also write this in VB or JavaScript. Even in custom XSLT it would be easier (use substring-before() a few times over, or build a recursive template), it'll be better than trying to hack together a bunch of stock functoids to complete this task.
Pictures of how this works (using inline C# to demo - you'd probably want this in an external assembly or a custom functoid for reusability; note that char can't actually be used, you have to use string as shown above):
It turns out we had to use a different script for each value (height, width and length) to extract those values from the string. Putting each in the scripting functiod using the following C# scripts worked for my map:
Length:
public decimal getLength(string weights)
{
string[] wgt;
wgt = weights.Split('x');
decimal len = Convert.ToDecimal(wgt[0]);
decimal wid = Convert.ToDecimal(wgt[1]);
decimal hgt = Convert.ToDecimal(wgt[2]);
return len;
}
Width:
public decimal getWidth(string weights)
{
string[] wgt;
wgt = weights.Split('x');
decimal len = Convert.ToDecimal(wgt[0]);
decimal wid = Convert.ToDecimal(wgt[1]);
decimal hgt = Convert.ToDecimal(wgt[2]);
return wid;
}
Height:
public decimal getHeight(string weights)
{
string[] wgt;
wgt = weights.Split('x');
decimal len = Convert.ToDecimal(wgt[0]);
decimal wid = Convert.ToDecimal(wgt[1]);
decimal hgt = Convert.ToDecimal(wgt[2]);
return hgt;
}
Related
There is a tag which is of type 2 ("required, empty if unknown"), with value representation Integer String which I would like to leave empty. I have tried creating the attribute like so:
var attribute = new DicomIntegerString(DicomTag.SeriesNumber, string.Empty);
The storing of the file works. When I read the file again, the result of the following call returns null:
var result = dicomDataset.GetString(DicomTag.SeriesNumber); // <-- this is null
How can I set the element to be correctly "zero-length", or "empty, if unknown"?
Thanks.
As already mentioned in the comments, the code to set an empty string in the dataset is correct:
dataset.AddOrUpdate(new DicomIntegerString(DicomTag.SeriesNumber, string.Empty));
Note that you could also write a null value:
dataset.AddOrUpdate(new DicomIntegerString(DicomTag.SeriesNumber, (string)null));
Writing out the dataset will create an empty tag for SeriesNumber in exactly the same way in both cases, as both cases are equivalent in DICOM.
The code to read the tag back is also correct, and the fact that it returns null is due to this equivalence, which creates an ambiguity in the interpretation of an empty string tag in DICOM. As the number of values in a DICOM string tag is defined only by the string itself (and the number of backslashes it contains), there is no difference between a tag with no values (which usually is represented by a null value), and a tag with an empty string (which would be represented by a "" value). For consistence with other tags it makes sense to return null for a tag with VM 0 - for non-string VRs there is no ambiguity here, as the length of a value is defined. For string values it could also make sense to return an empty string instead - both approaches have pros and cons, so in the end it is a design decision of the library creators.
In fo-dicom, it is probably best to handle both cases (e.g. using something like string.IsNullOrEmpty). If you read the value from a file dataset, you always get null, but if you are writing an empty string to a tag in a dataset (first version shown above) and read it back, you will get the same empty string back.
As an aside: in pydicom (the common Python DICOM library) there was a discussion about this same design decision, and in the end a configuration entry was added that defines the behavior (e.g. return None or an empty string for such values).
I'm developing a web app which is the transition from a previous desktop versión based in visual basic 6. I have to display times within a support ticket system of when the ticket first arrived,was first handled etc.
I'm running into certain problems when time formating since I seem to have to use several different methods to get what I want depending on the input and now I'm confused as to when I should use each.
For example, when using a system DateNow to get an answer in Hours, minutes and seconds this works fine:
Strings.Format(Date.Now, "HH:mm:ss")
But I have string values within the database, that are stored in a certain way and I cannot modify the database to have a timestamp field which I would prefer to store it, with the time, minutes and seconds scrunched up together as in where 13h,57mins,20secs ends in a string "135720". If I try the same
Dim info as string="135720"
Strings.Format(val(info),"HH:mm:ss)
The answer I get is the actual formating "HH:mm:ss", not the 13:57:20 I expected.
But if I use a transformed VB6 function in .net:
Microsoft.VisualBasic.Format(Val(Info), "##:##:##")
it works just fine.
I also have to use the Microsoft.VisualBasic.Format when trying to fix badly stored strings with partial times such as "1357" or just "135" to turn it into "13:57:00" or "13:50:00"using a case select based on the length of the string.
but I really don't want to be using old programming language in what is supposed to be a an updated app just because I don't finally understand how the new works and I have looked extensively into the documentation, but am none the wiser.
I did look within th comunity but didn't really find the answer either in such questions as:
Is there a way to programmatically convert VB6 Formatting strings to .NET Formatting strings?
A regular expression to validate .NET time format
Time format of datetime field in .net
Time format in asp.net page
Any help finding the new way I should be doing this and why would be greatly apreciated.
Thank You
You can use TimeSpan.
This Function will return a TimeSpan from your String-value.
Public Function GetTimeSpan(s As String)
Dim span As TimeSpan
s = s.Trim 'Trim spaces
'Check if string only contains numbers and if length is valid, else throw exception
If System.Text.RegularExpressions.Regex.IsMatch(s, "^[0-9]+$") AndAlso
s.Length >= 3 AndAlso
s.Length <= 6 Then
s = s.PadRight(6, "0")
Else
Throw New Exception("Invalid String!")
End If
TimeSpan.TryParseExact(s, "hhmmss", Globalization.CultureInfo.InvariantCulture, span)
Return span
End Function
And use it like this:
MessageBox.Show(GetTimeSpan("135700").ToString)
MessageBox.Show(GetTimeSpan("135").ToString)
I'm wondering whether to use matrix or query parameters in my URLs. I found an older discussion to that topic not satisfying.
Examples
URL with query params: http://some.where/thing?paramA=1¶mB=6542
URL with matrix params: http://some.where/thing;paramA=1;paramB=6542
At first sight matrix params seem to have only advantages:
more readable
no encoding and decoding of "&" in XML documents is required
URLs with "?" are not cached in many cases; URLs with matrix params are cached
matrix parameters can appear everywhere in the path and are not limited to its end
matrix parameters can have more than one value: paramA=val1,val2
But there are also disadvantages:
only a few frameworks like JAX-RS support matrix parameters
When a browser submits a form via GET, the params become query params. So it ends up in two kinds of parameters for the same task. To not confuse users of the REST services and limit the effort for the developers of the services, it would be easier to use always query params - in this area.
Since the developer of the service can choose a framework with matrix param support, the only remaining disadvantage would be that browsers create by default query parameters.
Are there any other disadvantages? What would you do?
The important difference is that matrix parameters apply to a particular path element while query parameters apply to the request as a whole. This comes into play when making a complex REST-style query to multiple levels of resources and sub-resources:
http://example.com/res/categories;name=foo/objects;name=green/?page=1
It really comes down to namespacing.
Note: The 'levels' of resources here are categories and objects.
If only query parameters were used for a multi-level URL, you would end up with
http://example.com/res?categories_name=foo&objects_name=green&page=1
This way you would also lose the clarity added by the locality of the parameters within the request. In addition, when using a framework like JAX-RS, all the query parameters would show up within each resource handler, leading to potential conflicts and confusion.
If your query has only one "level", then the difference is not really important and the two types of parameters are effectively interchangeable, however, query parameters are generally better supported and more widely recognized. In general, I would recommend that you stick with query parameters for things like HTML forms and simple, single-level HTTP APIs.
In addition to Tim Sylvester's answer I would like to provide an example of how matrix parameters can be handled with JAX-RS .
Matrix parameters at the last resource element
http://localhost:8080/res/categories/objects;name=green
You can access them using the #MatrixParam annotation
#GET
#Path("categories/objects")
public String objects(#MatrixParam("name") String objectName) {
return objectName;
}
Response
green
But like the Javadoc states
Note that the #MatrixParam annotation value refers to a name of a matrix parameter that resides in the last matched path segment of the Path-annotated Java structure that injects the value of the matrix parameter.
... what brings us to point 2
Matrix parameters in the middle of an URL
http://localhost:8080/res/categories;name=foo/objects;name=green
You can access matrix parameters anywhere using path variables and #PathParam PathSegment.
#GET
#Path("{categoryVar:categories}/objects")
public String objectsByCategory(#PathParam("categoryVar") PathSegment categorySegment,
#MatrixParam("name") String objectName) {
MultivaluedMap<String, String> matrixParameters = categorySegment.getMatrixParameters();
String categorySegmentPath = categorySegment.getPath();
String string = String.format("object %s, path:%s, matrixParams:%s%n", objectName,
categorySegmentPath, matrixParameters);
return string;
}
Response
object green, path:categories, matrixParams:[name=foo]
Since the matrix parameters are provided as a MultivaluedMap you can access each by
List<String> names = matrixParameters.get("name");
or if you only need the first one
String name = matrixParameters.getFirst("name");
Get all matrix parameters as one method parameter
http://localhost:8080/res/categories;name=foo/objects;name=green//attributes;name=size
Use a List<PathSegment> to get them all
#GET
#Path("all/{var:.+}")
public String allSegments(#PathParam("var") List<PathSegment> pathSegments) {
StringBuilder sb = new StringBuilder();
for (PathSegment pathSegment : pathSegments) {
sb.append("path: ");
sb.append(pathSegment.getPath());
sb.append(", matrix parameters ");
sb.append(pathSegment.getMatrixParameters());
sb.append("<br/>");
}
return sb.toString();
}
Response
path: categories, matrix parameters [name=foo]
path: objects, matrix parameters [name=green]
path: attributes, matrix parameters [name=size]
--Too important to be relegated to comment section.--
I'm not sure what the big deal is with matrix URLs. According to the w3c design article that TBL wrote, it was just a design idea and explicitly states that it's not a feature of the web. Things like relative URLs aren't implemented when using it. If you want to use it, that's fine; there's just no standard way to use it because it's not a standard.
— Steve Pomeroy.
So short answer is, if you need RS for business purpose, you are better off using request parameter.
Can I with ASP.NET Resources/Localization translate strings to depend on one or other (the English grammar) in a easy way, like I pass number 1 in my translate, it return "You have one car" or with 0, 2 and higher, "You have %n cars"?
Or I'm forced to have logic in my view to see if it's singular or plural?
JasonTrue wrote:
To the best of my knowledge, there isn't a language that requires something more complicated than singular/plural
Such languages do exist. In my native Polish, for example, there are three forms: for 1, for 2-4 and for zero and numbers greater than 4. Then after you reach 20, the forms for 21, 22-24 and 25+ are again different (same grammatical forms as for numerals 0-9). And yes, "you have 0 things" sounds awkward, because you're not likely to see that used in real life.
As a localization specialist, here's what I would recommend:
If possible, use forms which put the numeral at the end:
a: Number of cars: %d
This means the form of the noun "car" does not depend on the numeral, and 0 is as natural as any other number.
If the above is not acceptable, at least always make a complete sentence a translatable resource. That is, do use
b: You have 1 car.
c: You have %d cars.
But never split such units into smaller fragments such as
d: You have
e: car(s)
(Then somewhere else you have a non-localizable resource such as %s %d %s)
The difference is that while I cannot translate (c) directly, since the form of the noun will change, I can see the problem and I can change the sentence to form (a) in translation.
On the other hand, when I am faced with (d) and (e) fragments, there is no way to make sure the resulting sentence will be grammatical. Again: using fragments guarantees that in some languages the translation will be anything from grammatically awkward to completely broken.
This applies across the board, not just to numerals. For example, a fragment such as %s was deleted is also untranslatable, since the form of the verb will depend on the gender of the noun, which is unavailable here. The best I can do for Polish is the equivalent of Deleted: %s, but I can only do it as long as the %s placeholder is included in the translatable resource. If all I have is "was deleted" with no clue to the referent noun, I can only startle my dog by cursing aloud and in the end I still have to produce garbage grammar.
I've been working on a library to assist with internationalization of an application. It's called SmartFormat and is open-source on GitHub.
It contains "grammatical number" rules for many languages that determine the correct singular/plural form based on the locale. When translating a phrase that has words that depend on a quantity, you specify the multiple forms and the formatter chooses the correct form based on these rules.
For example:
var message = "There {0:is:are} {0} {0:item:items} remaining.";
var output = Smart.Format(culture, message, items.Count);
It has a very similar syntax to String.Format(...), but has tons of great features that make it easy to create natural and grammatically-correct messages.
It also deals with possible gender-specific formatting, lists, and much more.
moodforaday wrote:
This applies across the board, not just to numerals. For example, a fragment such as "%s was deleted" is also untranslatable, since the form of the verb will depend on the gender of the noun, which is unavailable here. The best I can do for Polish is the equivalent of "Deleted: %s", but I can only do it as long as the %s placeholder is included in the translatable resource. If all I have is "was deleted" with no clue to the referent noun, I can only startle my dog by cursing aloud and in the end I still have to produce garbage grammar.
The point I would like to make here, is never include a noun as a parameter. Many European languages modify the noun based on its gender, and in the case of German, whether it is the subject, object, or indirect object. Just use separate messages.
Instead of, "%s was deleted.", use a separate translation string for each type:
"The transaction was deleted."
"The user was deleted." etc.
This way, each string can be translated properly.
The solution to handle plural forms in different languages can be found here:
http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
While you can't use the above software in a commercial application (it's covered under GPL), you can use the same concepts. Their plural form expressions fit perfectly with lambda expressions in .NET. There are a limited number of plural form expressions that cover a large number of languages. You can map a particular language to a lambda expression that calculates which plural form to use based on the language. Then, look up the appropriate plural form in a .NET resx file.
There is nothing built in, we ended up coding something like this:
Another solution can be:
use place holders like {CAR} in the resource file strings
Maintain separate resource entries for singular and plural words for "car" :
CAR_SINGULAR car
CAR_PLURAL cars
Develop a class with this logic:
class MyResource
{
private List<string> literals = new List<string>();
public MyResource() { literals.Add("{CAR}") }
public static string GetLocalizedString(string key,bool isPlural)
{
string val = rm.GetString(key);
if(isPlural)
{
val = ReplaceLiteralWithPlural(val);
}
else
{
val = ReplaceLiteralWithSingular(val);
}
}
}
string ReplaceLiteralWithPlural(string val)
{
StringBuilder text = new StringBuilder(val)
foreach(string literal in literals)
{
text = text.Replace(literal,GetPluralKey(literal));
}
}
string GetPluralKey(string literal)
{
return literal + "_PLURAL";
}
This is still not possible in .NET natively. But it is a well known problem and already solved by gettext. It have native support for many technologies, even includes C# support. But looks like there is modern reimplementation now in .NET: https://github.com/VitaliiTsilnyk/NGettext
Orchard CMS uses GNU Gettext's PO files for localization and plural forms.
Here is their code where you can grab the idea:
https://github.com/OrchardCMS/OrchardCore/tree/main/src/OrchardCore/OrchardCore.Localization.Core
https://github.com/OrchardCMS/OrchardCore/tree/main/src/OrchardCore/OrchardCore.Localization.Abstractions
The logic needn't be in your view, but it's certainly not in the resource model the DotNet framework. Yours is a simple enough case that you can probably get away with creating a simple format string for singular, and one for plural. "You have 1 car."/"You have {0} cars." You then need to write a method that discriminates between the plural and singular case.
There are also a number of languages where there's no distinction between singular and plural, but this just requires a little duplication in the resource strings. (edit to add: gender and sometimes endings change depending on number of units in many languages, but this should be fine as long as you distinguish between singular and plural sentences, rather than just words).
Microsoft mostly gave up on semantically clever localization because it's hard to generalize even something like pluralization to 30+ languages. This is why you see such boring presentation of numeric quantities in most applications that are translated to many languages, along the lines of "Cars: {0}". That sounds lame, but surprisingly, the last time I checked, usability studies didn't actually favor the verbose natural language presentation in most cases.
An HTTP GET query string is a ordered sequence of key/value pairs:
?spam=eggs&spam=ham&foo=bar
Is, with certain semantics, equivalent to the following dictionary:
{'spam': ['eggs', 'ham'], 'foo': bar}
This happens to work well for boolean properties of that page being requested:
?expand=1&expand=2&highlight=7&highlight=9
{'expand': [1, 2], 'highlight': [7, 9]}
If you want to stop expanding the element with id 2, just pop it out of the expand value and urlencode the query string again. However, if you've got a more modal property (with 3+ choices), you really want to represent a structure like so:
{'highlight_mode': {7: 'blue', 9: 'yellow'}}
Where the values to the corresponding id keys are part of a known enumeration. What's the best way to encode this into a query string? I'm thinking of using a sequence of two-tuples like so:
?highlight_mode=(7,blue)&highlight_mode=(9,yellow)
Edit: It would also be nice to know any names that associate with the conventions. I know that there may not be any, but it's nice to be able to talk about something specific using a name instead of examples. Thanks!
The usual way is to do it like this:
highlight_mode[7]=blue&highlight_mode[9]=yellow
AFAIR, quite a few server-side languages actually support this out of the box and will produce a nice dictionary for these values.
I've also seen people JSON-encode the nested dictionary, then further encode it with BASE64 (or something similar), then pass the whole resulting mess as a single query string parameter.
Pretty ugly.
On the other hand, if you can get away with using POST, JSON is a really good way to pass this kind of information back and forth.
In many Web frameworks it's encoded differently from what you say.
{'foo': [1], 'bar': [2, 3], 'fred': 4}
would be:
?foo[]=1&bar[]=2&bar[]=3&fred=4
The reason array answers should be different from plain answers is so the decoding layer can automatically tell the less common foo case (array which just happens to have a single element) from extremely common fred case (single element).
This notation can be extrapolated to:
?highlight_mode[7]=blue&highlight_mode[9]=yellow
when you have a hash, not just an array.
I think this is pretty much what Rails and most frameworks which copy from Rails do.
Empty arrays, empty hashes, and lack of scalar value look identical in this encoding, but there's not much you can do about it.
This [] seems to be causing just a few flamewars. Some view it as unnecessary, because the browser, transport layer, and query string encoder don't care. The only thing that cares is automatic query string decoder. I support the Rails way of using []. The alternative would be having separate methods for extracting a scalar and extracting an array from querystring, as there's no automatic way to tell when program wants [1] when it wants 4.
This piece of code works for me with Python Backend-
import json, base64
param={
"key1":"val1",
"key2":[
{"lk1":"https://www.foore.in", "lk2":"https://www.foore.in/?q=1"},
{"lk1":"https://www.foore.in", "lk2":"https://www.foore.in/?q=1"}
]
}
encoded_param=base64.urlsafe_b64encode(json.dumps(param).encode())
encoded_param_ready=str(encoded_param)[2:-1]
#eyJrZXkxIjogInZhbDEiLCAia2V5MiI6IFt7ImxrMSI6ICJodHRwczovL3d3dy5mb29yZS5pbiIsICJsazIiOiAiaHR0cHM6Ly93d3cuZm9vcmUuaW4vP3E9MSJ9LCB7ImxrMSI6ICJodHRwczovL3d3dy5mb29yZS5pbiIsICJsazIiOiAiaHR0cHM6Ly93d3cuZm9vcmUuaW4vP3E9MSJ9XX0=
#In JS
var decoded_params = atob(decodeURI(encoded_param_ready));