There is any reliable way to construct string from given regex and "matched" results?
i am looking for something like:
stringConstruct('/My name is (?P<name>.*)/', {name: John});
with result "My name is John". So I need inverse functionality to regexp match.
Answer in any nonexotic language is suitable.
The short answer is "No" - that is not what regex is for.
but, you could do something like:
function stringConstruct($stringTemplate, $regex, $input){
if(preg_match($regex, $input)){
return str_replace($regex, $input, $stringTemplate);
} else {
return false;
}
}
But, you would have to use it like this, instead:
echo stringConstruct('My name is /(?P<name>.*)/', '/(?P<name>.*)/', "John");
You can write your own function. I did it once in Java, here's an example. sb is a string to be worked on. replaceMap is a (regexp, replaceStr) map:
public static boolean replaceAll(StringBuffer sb, Map<String,String> replaceMap)
{
boolean altered = false;
Iterator<String> it = replaceMap.keySet().iterator();
while (it.hasNext())
{
String toReplace = it.next();
Matcher mat = Pattern.compile(toReplace).matcher(sb);
while (mat.find())
{
if (!altered)
{
altered = true;
}
String str = (String) replaceMap.get(toReplace);
sb.replace(mat.start(), mat.end(), str);
mat.region(mat.start() + str.length(), sb.length());
}
}
return altered;
}
Related
I wrote this bit of code a a part of an exercise to check weather or not a string is palindromes. They program is working correctly in terms of checking the string but it does not return false when the string is not palindromes. What am I doing wrong? thanks
//convert the string to array
var stringArr = [ ];
var bool;
function palindrome(str) {
// make lowercase
var lowerCase = str.toLowerCase();
//remove numbers, special characters, and white spaces
var noNumbers = lowerCase.replace(/[0-9]/g, '');
var noSpecials = noNumbers.replace(/\W+/g, " ");
var finalString = noSpecials.replace(/\s/g, '');
stringArr = finalString.split("");
if (stringArr.sort(frontToBack)==stringArr.sort(backToFront)) {
bool = true;
}
else {
bool= false;
}
return bool;
}
function frontToBack (a,b) {return a-b;}
function backToFront (a,b) {return b-a;}
palindrome("eye");
if (stringArr.sort(frontToBack)==stringArr.sort(backToFront)) { is your problem.
In JavaScript, the sort method updates the value of the variable you are sorting. So in your comparison, once both sort's have run, both end up with the same value (since the second sort, effectively overrides the first).
For example.
var a = [1,7,3];
a.sort();
console.log(a); // will print 1,3,7
Edit: had a quick test, I think eavidan's suggestion is probably the best one.
Edit2: Just put together a quick version of a hopefully working palindrome function :)
function palindrome(str) { return str.split("").reverse().join("") == str;}
It is because string subtraction yields NaN, which means both sorted arrays are the same as the original.
Even if you did convert to ASCII coding, you sort the entire string, then for instance the string abba would be sorted front to back as aabb and back to front as bbaa. (edit: and also what Carl wrote about sort changing the original array. Still - sort is not the way to go here)
What you should do is just reverse the string (using reverse on the array) and compare.
You might do as follows;
var isPalindrome = s => { var t = s.toLowerCase()
.replace(/\s+/g,"");
return [].slice.call(t)
.reverse()
.every((b,i) => b === t[i]);
};
console.log(isPalindrome("Was it a car or a cat I saw"));
console.log(isPalindrome("This is not a palindrome"));
function pal()
{
var x=document.getElementById("a").value;
//input String
var y="";
//blank String
for (i=x.length-1;i>=0;i--)
//string run from backward
{
y=y+x[i];
//store string last to first one by one in blank string
}
if(x==y)
//compare blank and original string equal or not
{
console.log("Palindrome");
}
else
{
console.log("Not Palindrome ");
}
}
String.Format does not work in TypeScript.
Error:
The property 'format' does not exist on value of type
'{ prototype: String; fromCharCode(...codes: number[]): string;
(value?: any): string; new(value?: any): String; }'.
attributes["Title"] = String.format(
Settings.labelKeyValuePhraseCollection["[WAIT DAYS]"],
originalAttributes.Days
);
String Interpolation
Note: As of TypeScript 1.4, string interpolation is available in TypeScript:
var a = "Hello";
var b = "World";
var text = `${a} ${b}`
This will compile to:
var a = "Hello";
var b = "World";
var text = a + " " + b;
String Format
The JavaScript String object doesn't have a format function. TypeScript doesn't add to the native objects, so it also doesn't have a String.format function.
For TypeScript, you need to extend the String interface and then you need to supply an implementation:
interface String {
format(...replacements: string[]): string;
}
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
}
You can then use the feature:
var myStr = 'This is an {0} for {0} purposes: {1}';
alert(myStr.format('example', 'end'));
You could also consider string interpolation (a feature of Template Strings), which is an ECMAScript 6 feature - although to use it for the String.format use case, you would still need to wrap it in a function in order to supply a raw string containing the format and then positional arguments. It is more typically used inline with the variables that are being interpolated, so you'd need to map using arguments to make it work for this use case.
For example, format strings are normally defined to be used later... which doesn't work:
// Works
var myFormatString = 'This is an {0} for {0} purposes: {1}';
// Compiler warnings (a and b not yet defines)
var myTemplateString = `This is an ${a} for ${a} purposes: ${b}`;
So to use string interpolation, rather than a format string, you would need to use:
function myTemplate(a: string, b: string) {
var myTemplateString = `This is an ${a} for ${a} purposes: ${b}`;
}
alert(myTemplate('example', 'end'));
The other common use case for format strings is that they are used as a resource that is shared. I haven't yet discovered a way to load a template string from a data source without using eval.
You can use TypeScript's native string interpolation in case if your only goal to eliminate ugly string concatenations and boring string conversions:
var yourMessage = `Your text ${yourVariable} your text continued ${yourExpression} and so on.`
NOTE:
At the right side of the assignment statement the delimiters are neither single or double quotes, instead a special char called backtick or grave accent.
The TypeScript compiler will translate your right side special literal to a string concatenation expression. With other words this syntax does not rely on the ECMAScript 6 feature, instead a native TypeScript feature. Your generated javascript code remains compatible.
I solved it like this;
1.Created a function
export function FormatString(str: string, ...val: string[]) {
for (let index = 0; index < val.length; index++) {
str = str.replace(`{${index}}`, val[index]);
}
return str;
}
2.Used it like the following;
FormatString("{0} is {1} {2}", "This", "formatting", "hack");
You can declare it yourself quite easily:
interface StringConstructor {
format: (formatString: string, ...replacement: any[]) => string;
}
String.format('','');
This is assuming that String.format is defined elsewhere. e.g. in Microsoft Ajax Toolkit : http://www.asp.net/ajaxlibrary/Reference.String-format-Function.ashx
If you are using NodeJS, you can use the build-in util function:
import * as util from "util";
util.format('My string: %s', 'foo');
Document can be found here:
https://nodejs.org/api/util.html#util_util_format_format_args
FIDDLE: https://jsfiddle.net/1ytxfcwx/
NPM: https://www.npmjs.com/package/typescript-string-operations
GITHUB: https://github.com/sevensc/typescript-string-operations
I implemented a class for String. Its not perfect but it works for me.
use it i.e. like this:
var getFullName = function(salutation, lastname, firstname) {
return String.Format('{0} {1:U} {2:L}', salutation, lastname, firstname)
}
export class String {
public static Empty: string = "";
public static isNullOrWhiteSpace(value: string): boolean {
try {
if (value == null || value == 'undefined')
return false;
return value.replace(/\s/g, '').length < 1;
}
catch (e) {
return false;
}
}
public static Format(value, ...args): string {
try {
return value.replace(/{(\d+(:.*)?)}/g, function (match, i) {
var s = match.split(':');
if (s.length > 1) {
i = i[0];
match = s[1].replace('}', '');
}
var arg = String.formatPattern(match, args[i]);
return typeof arg != 'undefined' && arg != null ? arg : String.Empty;
});
}
catch (e) {
return String.Empty;
}
}
private static formatPattern(match, arg): string {
switch (match) {
case 'L':
arg = arg.toLowerCase();
break;
case 'U':
arg = arg.toUpperCase();
break;
default:
break;
}
return arg;
}
}
EDIT:
I extended the class and created a repository on github. It would be great if you can help to improve it!
https://github.com/sevensc/typescript-string-operations
or download the npm package
https://www.npmjs.com/package/typescript-string-operations
As a workaround which achieves the same purpose, you may use the sprintf-js library and types.
I got it from another SO answer.
I create a method by mixing answers of #AnandShanbhag #Fenton
formatMessage(message: string, ...params: any[]):string {
let regexp = /{(\d+)}/g;
return message.replace(regexp, function (match, number): string {
return (number < params.length && typeof params[number] != "undefined") ? params[number] : match;
});
}
I am using TypeScript version 3.6 and I can do like this:
let templateStr = 'This is an {0} for {1} purpose';
const finalStr = templateStr.format('example', 'format'); // This is an example for format purpose
How can I check a JavaScript string is in a RegExp format, then convert it to RegExp?
I found a way with RegExp, but the rule is too complex to make it right.
function str2Regex(str){
var rule = /\/(\\[^\x00-\x1f]|\[(\\[^\x00-\x1f]|[^\x00-\x1f\\\/])*\]|[^\x00-\x1f\\\/\[])+\/([gim]*)/;
var match = str.match(rule);
return match ? new RegExp(match[1],match[3]) : str;
}
Now I'm using /\/(.*)\/(?=[igm]*)([igm]*)/ which works.
The simplest way, and probably the most correct, is to use try/catch :
try {
r = new RegExp(str);
} catch(error) {
// no good
}
You get a SyntaxError when the string doesn't match a well formed regular expression.
If you want to test a string whose value is like a compiled regular expression (for example "/\b=\b/g", you can use such a function :
function checkCompiledRegex(str) {
if (str[0]!='/') return false;
var i = str.lastIndexOf('/');
if (i<=0) return false;
try {
new RegExp(str.slice(1, i), str.slice(i+1));
} catch(error) {
return false;
}
return true;
}
Can anyone tell me why does this not work for integers but works for characters? I really hate reg expressions since they are cryptic but will if I have too. Also I want to include the "-()" as well in the valid characters.
String.prototype.Contains = function (str) {
return this.indexOf(str) != -1;
};
var validChars = '0123456789';
var str = $("#textbox1").val().toString();
if (str.Contains(validChars)) {
alert("found");
} else {
alert("not found");
}
Review
String.prototype.Contains = function (str) {
return this.indexOf(str) != -1;
};
This String "method" returns true if str is contained within itself, e.g. 'hello world'.indexOf('world') != -1would returntrue`.
var validChars = '0123456789';
var str = $("#textbox1").val().toString();
The value of $('#textbox1').val() is already a string, so the .toString() isn't necessary here.
if (str.Contains(validChars)) {
alert("found");
} else {
alert("not found");
}
This is where it goes wrong; effectively, this executes '1234'.indexOf('0123456789') != -1; it will almost always return false unless you have a huge number like 10123456789.
What you could have done is test each character in str whether they're contained inside '0123456789', e.g. '0123456789'.indexOf(c) != -1 where c is a character in str. It can be done a lot easier though.
Solution
I know you don't like regular expressions, but they're pretty useful in these cases:
if ($("#textbox1").val().match(/^[0-9()]+$/)) {
alert("valid");
} else {
alert("not valid");
}
Explanation
[0-9()] is a character class, comprising the range 0-9 which is short for 0123456789 and the parentheses ().
[0-9()]+ matches at least one character that matches the above character class.
^[0-9()]+$ matches strings for which ALL characters match the character class; ^ and $ match the beginning and end of the string, respectively.
In the end, the whole expression is padded on both sides with /, which is the regular expression delimiter. It's short for new RegExp('^[0-9()]+$').
Assuming you are looking for a function to validate your input, considering a validChars parameter:
String.prototype.validate = function (validChars) {
var mychar;
for(var i=0; i < this.length; i++) {
if(validChars.indexOf(this[i]) == -1) { // Loop through all characters of your string.
return false; // Return false if the current character is not found in 'validChars' string.
}
}
return true;
};
var validChars = '0123456789';
var str = $("#textbox1").val().toString();
if (str.validate(validChars)) {
alert("Only valid characters were found! String validates!");
} else {
alert("Invalid Char found! String doesn't validate.");
}
However, This is quite a load of code for a string validation. I'd recommend looking into regexes, instead. (Jack's got a nice answer up here)
You are passing the entire list of validChars to indexOf(). You need to loop through the characters and check them one-by-one.
Demo
String.prototype.Contains = function (str) {
var mychar;
for(var i=0; i<str.length; i++)
{
mychar = this.substr(i, 1);
if(str.indexOf(mychar) == -1)
{
return false;
}
}
return this.length > 0;
};
To use this on integers, you can convert the integer to a string with String(), like this:
var myint = 33; // define integer
var strTest = String(myint); // convert to string
console.log(strTest.Contains("0123456789")); // validate against chars
I'm only guessing, but it looks like you are trying to check a phone number. One of the simple ways to change your function is to check string value with RegExp.
String.prototype.Contains = function(str) {
var reg = new RegExp("^[" + str +"]+$");
return reg.test(this);
};
But it does not check the sequence of symbols in string.
Checking phone number is more complicated, so RegExp is a good way to do this (even if you do not like it). It can look like:
String.prototype.ContainsPhone = function() {
var reg = new RegExp("^\\([0-9]{3}\\)[0-9]{3}-[0-9]{2}-[0-9]{2}$");
return reg.test(this);
};
This variant will check phones like "(123)456-78-90". It not only checks for a list of characters, but also checks their sequence in string.
Thank you all for your answers! Looks like I'll use regular expressions. I've tried all those solutions but really wanted to be able to pass in a string of validChars but instead I'll pass in a regex..
This works for words, letters, but not integers. I wanted to know why it doesn't work for integers. I wanted to be able to mimic the FilteredTextBoxExtender from the ajax control toolkit in MVC by using a custom Attribute on a textBox
How can I quickly validate if a string is alphabetic only, e.g
var str = "!";
alert(isLetter(str)); // false
var str = "a";
alert(isLetter(str)); // true
Edit : I would like to add parenthesis i.e () to an exception, so
var str = "(";
or
var str = ")";
should also return true.
Regular expression to require at least one letter, or paren, and only allow letters and paren:
function isAlphaOrParen(str) {
return /^[a-zA-Z()]+$/.test(str);
}
Modify the regexp as needed:
/^[a-zA-Z()]*$/ - also returns true for an empty string
/^[a-zA-Z()]$/ - only returns true for single characters.
/^[a-zA-Z() ]+$/ - also allows spaces
Here you go:
function isLetter(s)
{
return s.match("^[a-zA-Z\(\)]+$");
}
If memory serves this should work in javascript:
function containsOnlyLettersOrParenthesis(str)
(
return str.match(/^([a-z\(\)]+)$/i);
)
You could use Regular Expressions...
functions isLetter(str) {
return str.match("^[a-zA-Z()]+$");
}
Oops... my bad... this is wrong... it should be
functions isLetter(str) {
return "^[a-zA-Z()]+$".test(str);
}
As the other answer says... sorry