I am using the Scanner methods nextInt() and nextLine() for reading input.
It looks like this:
System.out.println("Enter numerical value");
int option;
option = input.nextInt(); // Read numerical value from input
System.out.println("Enter 1st string");
String string1 = input.nextLine(); // Read 1st string (this is skipped)
System.out.println("Enter 2nd string");
String string2 = input.nextLine(); // Read 2nd string (this appears right after reading numerical value)
The problem is that after entering the numerical value, the first input.nextLine() is skipped and the second input.nextLine() is executed, so that my output looks like this:
Enter numerical value
3 // This is my input
Enter 1st string // The program is supposed to stop here and wait for my input, but is skipped
Enter 2nd string // ...and this line is executed and waits for my input
I tested my application and it looks like the problem lies in using input.nextInt(). If I delete it, then both string1 = input.nextLine() and string2 = input.nextLine() are executed as I want them to be.
That's because the Scanner.nextInt method does not read the newline character in your input created by hitting "Enter," and so the call to Scanner.nextLine returns after reading that newline.
You will encounter the similar behaviour when you use Scanner.nextLine after Scanner.next() or any Scanner.nextFoo method (except nextLine itself).
Workaround:
Either put a Scanner.nextLine call after each Scanner.nextInt or Scanner.nextFoo to consume rest of that line including newline
int option = input.nextInt();
input.nextLine(); // Consume newline left-over
String str1 = input.nextLine();
Or, even better, read the input through Scanner.nextLine and convert your input to the proper format you need. For example, you may convert to an integer using Integer.parseInt(String) method.
int option = 0;
try {
option = Integer.parseInt(input.nextLine());
} catch (NumberFormatException e) {
e.printStackTrace();
}
String str1 = input.nextLine();
The problem is with the input.nextInt() method; it only reads the int value. So when you continue reading with input.nextLine() you receive the "\n" Enter key. So to skip this you have to add the input.nextLine().
Try it like this, instead:
System.out.print("Insert a number: ");
int number = input.nextInt();
input.nextLine(); // This line you have to add (It consumes the \n character)
System.out.print("Text1: ");
String text1 = input.nextLine();
System.out.print("Text2: ");
String text2 = input.nextLine();
It's because when you enter a number then press Enter, input.nextInt() consumes only the number, not the "end of line". When input.nextLine() executes, it consumes the "end of line" still in the buffer from the first input.
Instead, use input.nextLine() immediately after input.nextInt()
There seem to be many questions about this issue with java.util.Scanner. I think a more readable/idiomatic solution would be to call scanner.skip("[\r\n]+") to drop any newline characters after calling nextInt().
EDIT: as #PatrickParker noted below, this will cause an infinite loop if user inputs any whitespace after the number. See their answer for a better pattern to use with skip: https://stackoverflow.com/a/42471816/143585
TL;DR
nextLine() is safe to call when (a) it is first reading instruction, (b) previous reading instruction was also nextLine().
If you are not sure that either of above is true you can use scanner.skip("\\R?") before calling scanner.nextLine() since calls like next() nextInt() will leave potential line separator - created by return key which will affect result of nextLine(). The .skip("\\R?") will let us consume this unnecessary line separator.
skip uses regex where
\R represents line separators
? will make \R optional - which will prevent skip method from:
waiting for matching sequence
in case of reaching end of still opened source of data like System.in, input stream from socket, etc.
throwing java.util.NoSuchElementException in case of
terminated/closed source of data,
or when existing data doesn't match what we want to skip
Things you need to know:
text which represents few lines also contains non-printable characters between lines (we call them line separators) like
carriage return (CR - in String literals represented as "\r")
line feed (LF - in String literals represented as "\n")
when you are reading data from the console, it allows the user to type his response and when he is done he needs to somehow confirm that fact. To do so, the user is required to press "enter"/"return" key on the keyboard.
What is important is that this key beside ensuring placing user data to standard input (represented by System.in which is read by Scanner) also sends OS dependant line separators (like for Windows \r\n) after it.
So when you are asking the user for value like age, and user types 42 and presses enter, standard input will contain "42\r\n".
Problem
Scanner#nextInt (and other Scanner#nextType methods) doesn't allow Scanner to consume these line separators. It will read them from System.in (how else Scanner would know that there are no more digits from the user which represent age value than facing whitespace?) which will remove them from standard input, but it will also cache those line separators internally. What we need to remember, is that all of the Scanner methods are always scanning starting from the cached text.
Now Scanner#nextLine() simply collects and returns all characters until it finds line separators (or end of stream). But since line separators after reading the number from the console are found immediately in Scanner's cache, it returns empty String, meaning that Scanner was not able to find any character before those line separators (or end of stream).
BTW nextLine also consumes those line separators.
Solution
So when you want to ask for number and then for entire line while avoiding that empty string as result of nextLine, either
consume line separator left by nextInt from Scanners cache by
calling nextLine,
or IMO more readable way would be by calling skip("\\R") or skip("\r\n|\r|\n") to let Scanner skip part matched by line separator (more info about \R: https://stackoverflow.com/a/31060125)
don't use nextInt (nor next, or any nextTYPE methods) at all. Instead read entire data line-by-line using nextLine and parse numbers from each line (assuming one line contains only one number) to proper type like int via Integer.parseInt.
BTW: Scanner#nextType methods can skip delimiters (by default all whitespaces like tabs, line separators) including those cached by scanner, until they will find next non-delimiter value (token). Thanks to that for input like "42\r\n\r\n321\r\n\r\n\r\nfoobar" code
int num1 = sc.nextInt();
int num2 = sc.nextInt();
String name = sc.next();
will be able to properly assign num1=42 num2=321 name=foobar.
It does that because input.nextInt(); doesn't capture the newline. you could do like the others proposed by adding an input.nextLine(); underneath.
Alternatively you can do it C# style and parse a nextLine to an integer like so:
int number = Integer.parseInt(input.nextLine());
Doing this works just as well, and it saves you a line of code.
Instead of input.nextLine() use input.next(), that should solve the problem.
Modified code:
public static Scanner input = new Scanner(System.in);
public static void main(String[] args)
{
System.out.print("Insert a number: ");
int number = input.nextInt();
System.out.print("Text1: ");
String text1 = input.next();
System.out.print("Text2: ");
String text2 = input.next();
}
If you want to read both strings and ints, a solution is to use two Scanners:
Scanner stringScanner = new Scanner(System.in);
Scanner intScanner = new Scanner(System.in);
intScanner.nextInt();
String s = stringScanner.nextLine(); // unaffected by previous nextInt()
System.out.println(s);
intScanner.close();
stringScanner.close();
In order to avoid the issue, use nextLine(); immediately after nextInt(); as it helps in clearing out the buffer. When you press ENTER the nextInt(); does not capture the new line and hence, skips the Scanner code later.
Scanner scanner = new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer
If you want to scan input fast without getting confused into Scanner class nextLine() method , Use Custom Input Scanner for it .
Code :
class ScanReader {
/**
* #author Nikunj Khokhar
*/
private byte[] buf = new byte[4 * 1024];
private int index;
private BufferedInputStream in;
private int total;
public ScanReader(InputStream inputStream) {
in = new BufferedInputStream(inputStream);
}
private int scan() throws IOException {
if (index >= total) {
index = 0;
total = in.read(buf);
if (total <= 0) return -1;
}
return buf[index++];
}
public char scanChar(){
int c=scan();
while (isWhiteSpace(c))c=scan();
return (char)c;
}
public int scanInt() throws IOException {
int integer = 0;
int n = scan();
while (isWhiteSpace(n)) n = scan();
int neg = 1;
if (n == '-') {
neg = -1;
n = scan();
}
while (!isWhiteSpace(n)) {
if (n >= '0' && n <= '9') {
integer *= 10;
integer += n - '0';
n = scan();
}
}
return neg * integer;
}
public String scanString() throws IOException {
int c = scan();
while (isWhiteSpace(c)) c = scan();
StringBuilder res = new StringBuilder();
do {
res.appendCodePoint(c);
c = scan();
} while (!isWhiteSpace(c));
return res.toString();
}
private boolean isWhiteSpace(int n) {
if (n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1) return true;
else return false;
}
public long scanLong() throws IOException {
long integer = 0;
int n = scan();
while (isWhiteSpace(n)) n = scan();
int neg = 1;
if (n == '-') {
neg = -1;
n = scan();
}
while (!isWhiteSpace(n)) {
if (n >= '0' && n <= '9') {
integer *= 10;
integer += n - '0';
n = scan();
}
}
return neg * integer;
}
public void scanLong(long[] A) throws IOException {
for (int i = 0; i < A.length; i++) A[i] = scanLong();
}
public void scanInt(int[] A) throws IOException {
for (int i = 0; i < A.length; i++) A[i] = scanInt();
}
public double scanDouble() throws IOException {
int c = scan();
while (isWhiteSpace(c)) c = scan();
int sgn = 1;
if (c == '-') {
sgn = -1;
c = scan();
}
double res = 0;
while (!isWhiteSpace(c) && c != '.') {
if (c == 'e' || c == 'E') {
return res * Math.pow(10, scanInt());
}
res *= 10;
res += c - '0';
c = scan();
}
if (c == '.') {
c = scan();
double m = 1;
while (!isWhiteSpace(c)) {
if (c == 'e' || c == 'E') {
return res * Math.pow(10, scanInt());
}
m /= 10;
res += (c - '0') * m;
c = scan();
}
}
return res * sgn;
}
}
Advantages :
Scans Input faster than BufferReader
Reduces Time Complexity
Flushes Buffer for every next input
Methods :
scanChar() - scan single character
scanInt() - scan Integer value
scanLong() - scan Long value
scanString() - scan String value
scanDouble() - scan Double value
scanInt(int[] array) - scans complete Array(Integer)
scanLong(long[] array) - scans complete Array(Long)
Usage :
Copy the Given Code below your java code.
Initialise Object for Given Class
ScanReader sc = new ScanReader(System.in);
3. Import necessary Classes :
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
4. Throw IOException from your main method to handle Exception
5. Use Provided Methods.
6. Enjoy
Example :
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
class Main{
public static void main(String... as) throws IOException{
ScanReader sc = new ScanReader(System.in);
int a=sc.scanInt();
System.out.println(a);
}
}
class ScanReader....
sc.nextLine() is better as compared to parsing the input.
Because performance wise it will be good.
I guess I'm pretty late to the party..
As previously stated, calling input.nextLine() after getting your int value will solve your problem. The reason why your code didn't work was because there was nothing else to store from your input (where you inputted the int) into string1. I'll just shed a little more light to the entire topic.
Consider nextLine() as the odd one out among the nextFoo() methods in the Scanner class. Let's take a quick example.. Let's say we have two lines of code like the ones below:
int firstNumber = input.nextInt();
int secondNumber = input.nextInt();
If we input the value below (as a single line of input)
54 234
The value of our firstNumber and secondNumber variable become 54 and 234 respectively. The reason why this works this way is because a new line feed (i.e \n) IS NOT automatically generated when the nextInt() method takes in the values. It simply takes the "next int" and moves on. This is the same for the rest of the nextFoo() methods except nextLine().
nextLine() generates a new line feed immediately after taking a value; this is what #RohitJain means by saying the new line feed is "consumed".
Lastly, the next() method simply takes the nearest String without generating a new line; this makes this the preferential method for taking separate Strings within the same single line.
I hope this helps.. Merry coding!
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int i = scan.nextInt();
scan.nextLine();
double d = scan.nextDouble();
scan.nextLine();
String s = scan.nextLine();
System.out.println("String: " + s);
System.out.println("Double: " + d);
System.out.println("Int: " + i);
}
if I expect a non-empty input
avoids:
– loss of data if the following input is eaten by an unchecked scan.nextLine() as workaround
– loss of data due to only partially read lines because scan.nextLine() was replaced by scan.next() (enter: "yippie ya yeah")
– Exceptions that are thrown when parsing input with Scanner methods (read first, parse afterwards)
public static Function<Scanner,String> scanLine = (scan -> {
String s = scan.nextLine();
return( s.length() == 0 ? scan.nextLine() : s );
});
used in above example:
System.out.println("Enter numerical value");
int option = input.nextInt(); // read numerical value from input
System.out.println("Enter 1st string");
String string1 = scanLine.apply( input ); // read 1st string
System.out.println("Enter 2nd string");
String string2 = scanLine.apply( input ); // read 2nd string
Use 2 scanner objects instead of one
Scanner input = new Scanner(System.in);
System.out.println("Enter numerical value");
int option;
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();
In one of my usecase, I had the scenario of reading a string value preceded by a couple of integer values. I had to use a "for / while loop" to read the values. And none of the above suggestions worked in this case.
Using input.next() instead of input.nextLine() fixed the issue. Hope this might be helpful for those dealing with similar scenario.
As nextXXX() methods don't read newline, except nextLine(). We can skip the newline after reading any non-string value (int in this case) by using scanner.skip() as below:
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(x);
double y = sc.nextDouble();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(y);
char z = sc.next().charAt(0);
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(z);
String hello = sc.nextLine();
System.out.println(hello);
float tt = sc.nextFloat();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(tt);
Use this code it will fix your problem.
System.out.println("Enter numerical value");
int option;
option = input.nextInt(); // Read numerical value from input
input.nextLine();
System.out.println("Enter 1st string");
String string1 = input.nextLine(); // Read 1st string (this is skipped)
System.out.println("Enter 2nd string");
String string2 = input.nextLine(); // Read 2nd string (this appears right after reading numerical value)
To resolve this problem just make a scan.nextLine(), where scan is an instance of the Scanner object. For example, I am using a simple HackerRank Problem for the explanation.
package com.company;
import java.util.Scanner;
public class hackerrank {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int i = scan.nextInt();
double d = scan.nextDouble();
scan.nextLine(); // This line shall stop the skipping the nextLine()
String s = scan.nextLine();
scan.close();
// Write your code here.
System.out.println("String: " + s);
System.out.println("Double: " + d);
System.out.println("Int: " + i);
}
}
The nextLine() will read enter directly as an empty line without waiting for the text.
Simple solution by adding an extra scanner to consume the empty line:
System.out.println("Enter numerical value");
int option;
option = input.nextInt(); // Read numerical value from input
input.nextLine();
System.out.println("Enter 1st string");
String string1 = input.nextLine(); // Read 1st string (this is skipped)
System.out.println("Enter 2nd string");
String string2 = input.nextLine(); // Read 2nd string (this appears right after reading numerical value)
This is a very basic problem for beginner coders in java. The same problem I also have faced when I started java (Self Taught).
Actually, when we take an input of integer dataType, it reads only integer value and leaves the newLine(\n) character and this line(i.e. leaved new line by integer dynamic input )creates the problem when we try to take a new input.
eg. Like if we take the integer input and then after try to take an String input.
value1=sc.nextInt();
value2=sc.nextLine();
the value2 will auto read the newLine character and will not take the user input.
Solution:
just we need to add one line of code before taking the next user input i.e.
sc.nextLine();
or
value1=sc.nextInt();
sc.nextLine();
value2=sc.nextLine();
Note: don't forget to close the Scanner to prevent memory leak;
Scanner scan = new Scanner(System.in);
int i = scan.nextInt();
scan.nextLine();//to Ignore the rest of the line after (integer input)nextInt()
double d=scan.nextDouble();
scan.nextLine();
String s=scan.nextLine();
scan.close();
System.out.println("String: " + s);
System.out.println("Double: " + d);
System.out.println("Int: " + i);
Why not use a new Scanner for every reading? Like below. With this approach you will not confront your problem.
int i = new Scanner(System.in).nextInt();
The problem is with the input.nextInt() method - it only reads the int value. So when you continue reading with input.nextLine() you receive the "\n" Enter key. So to skip this you have to add the input.nextLine(). Hope this should be clear now.
Try it like that:
System.out.print("Insert a number: ");
int number = input.nextInt();
input.nextLine(); // This line you have to add (It consumes the \n character)
System.out.print("Text1: ");
String text1 = input.nextLine();
System.out.print("Text2: ");
String text2 = input.nextLine();
Related
I'm working on my final project of the Winter 2017 quarter to demonstrate how to use Regular Expressions in both C# and JavaScript code behind pages. I've got the C# version of my demonstration program done, but the JavaScript version is making me pull what little hair I have left on my head out (no small achievement since I got a fresh buzz cut this morning!). The problem involves not getting any output after applying a Regular Expression in a While loop to get each instance of the expression and printing it out.
On my HTML page I have an input textarea, seven radio buttons, an output textarea, and two buttons underneath (one button is to move the output text to the input area to perform multiple iterations of applying expressions, and the other button to clear all textareas for starting from scratch). Each radio button links to a function that applies a regular expression to the text in the input area. Five of my seven functions work; the sixth is the one I can't figure out, and the seventh is essentially the same but with a slightly different RegEx pattern, so if I fix the sixth function, the seventh function will be a snap.
(I tried to insert/upload a JPG of the front end, but the photo upload doesn't seem to be working. Hopefully you get the drift of what I've set up.)
Here are my problem children from my JS code behind:
// RegEx_Demo_JS.js - code behind for RegEx_Demo_JS
var inputString; // Global variable for the input from the input text box.
var pattern; // Global variable for the regular expression.
var result; // Global variable for the result of applying the regular expression to the user input.
// Initializes a new instance of the StringBuilder class
// and appends the given value if supplied
function StringBuilder()
{
var strings = [];
this.append = function (string)
{
string = verify(string);
if (string.length > 0) strings[strings.length] = string;
}
this.appendLine = function (string)
{
string = verify(string);
if (this.isEmpty())
{
if (string.length > 0) strings[strings.length] = string;
else return;
}
else strings[strings.length] = string.length > 0 ? "\r\n" + string : "\r\n";
}
this.clear = function () { strings = []; };
this.isEmpty = function () { return strings.length == 0; };
this.toString = function () { return strings.join(""); };
var verify = function (string)
{
if (!defined(string)) return "";
if (getType(string) != getType(new String())) return String(string);
return string;
}
var defined = function (el)
{
// Changed per Ryan O'Hara's comment:
return el != null && typeof(el) != "undefined";
}
var getType = function (instance)
{
if (!defined(instance.constructor)) throw Error("Unexpected object type");
var type = String(instance.constructor).match(/function\s+(\w+)/);
return defined(type) ? type[1] : "undefined";
}
}
Within the code of the second radio button (which will be the seventh and last function to complete), I tested the ScriptBuilder with data in a local variable, and it ran successfully and produced output into the output textarea. But I get no output from this next function that invokes a While loop:
function RegEx_Match_TheOnly_AllInstances()
{
inputString = document.getElementById("txtUserInput").value;
pattern = /(\s+the\s+)/ig; // Using an Flag (/i) to select either lowercase or uppercase version. Finds first occurrence either as a standalone word or inside a word.
//result = pattern.exec(inputString); // Finds the first index location
var arrResult; // Array for the results of the search.
var sb = getStringBuilder(); // Variable to hold iterations of the result and the text
while ((arrResult = pattern.exec(inputString)) !==null)
{
sb.appendLine = "Match: " + arrResult[0] ;
}
document.getElementById("txtRegExOutput").value = sb.toString();
/* Original code from C# version:
// string pattern = #"\s+(?i)the\s+"; // Same as above, but using Option construct for case insensitive search.
string pattern = #"(^|\s+)(?i)the(\W|\s+)";
MatchCollection matches = Regex.Matches(userTextInput, pattern);
StringBuilder outputString = new StringBuilder();
foreach (Match match in matches)
{
string outputRegExs = "Match: " + "\"" + match.Value + "\"" + " at index [" + match.Index + ","
+ (match.Index + match.Length) + "]" + "\n";
outputString.Append(outputRegExs);
}
txtRegExOutput.Text = outputString.ToString();
*/
} // End RegEx_Match_The_AllInstances
I left the commented code in to show what I had used in the C# code behind version to illustrate what I'm trying to accomplish.
The test input/string I used for this function is:
Don’t go there. If you want to be the Man, you have to beat The Man.
That should return two hits. Ideally, I want it to show the word that it found and the index where it found the word, but at this point I'd be happy to just get some output showing every instance it found, and then build on that with the index and possibly the lastIndex.
So, is my problem in my While loop, the way I'm applying the StringBuilder, or a combination of the two? I know the StringBuilder code works, at least when not being used in a loop and using some test data from the site I found that code. And the code for simply finding the first instance of "the" as a standalone or inside another word does work and returns output, but that doesn't use a loop.
I've looked through Stack Overflow and several other JavaScript websites for inspiration, but nothing I've tried so far has worked. I appreciate any help anyone can provide! (If you need me to post any other code, please advise and I'll be happy to oblige.)
So I have a variable in Javascript that can be both String and int, I need to send it to a java method. I though that, since it's easier to change a number into a string instead of the opposite, I set the variable into a string. I'm gonna post some code
This is obviously the javascript, the variable valore is the one that can be both Int and string
$(".save").click(function() {
var valore = $("#valore").val();
var connettore = $("#connettore option:selected").text().split(" ").join("");
$.get("select"+connettore+".do", {
nomecampo: $("#colonnaRiferim").val().toLowerCase(),
valore: valore
}, function (data) {
for (var i = 0; i < data.connettore.length; i++) {
var conn = data.connettore[i];
}
}
);
This is the Java function
#RequestMapping("selectCompensi")
#ResponseBody
#Transactional
public ModelWrapper<List<TracciatoCompensi>> selectCompensi(#RequestParam String nomecampo,
#RequestParam String valore){
Session s = hibernateFactory.getCurrentSession();
ModelWrapper<List<TracciatoCompensi>> resp = new ModelWrapper<List<TracciatoCompensi>>();
Criteria c = s.createCriteria(TracciatoCompensi.class)
.add(Restrictions.eq(nomecampo, valore));
List<TracciatoCompensi> aList = (List<TracciatoCompensi>) c.list();
Query query = s.createSQLQuery("INSERT INTO tracciato_compensi_clone (CODICEORDINE, CODICESERVIZIO, CODICEUNIVOCOCOMPONENTE, COEFFICIENTECANONEMESE, "+nomecampo+", compensi1, rev, mod_time, mod_user) ("
+"SELECT CODICEORDINE, CODICESERVIZIO, CODICEUNIVOCOCOMPONENTE, COEFFICIENTECANONEMESE, "+nomecampo+", "+nomecampo+", rev, mod_time, mod_user FROM tracciato_compensi WHERE "+nomecampo+" = '"+valore+"')");
resp.put("connettore", aList);
query.executeUpdate();
return resp;
}
You can ignore the Query, that stuff works, as so does the criteria and the rest. My problem seems obvious, if valore is numeric, then the function crash,
I tried to add a random character to the number, and I tried to convert it using toString() into javascript but even if I use the isNumeric() function of jquery and it says that it isn't numeric, it still crashes
The method you're looking for probably is String.valueOf(Object):
String valore1 = "5";
System.out.println(String.valueOf(valore1));
int valore2 = 5;
System.out.println(String.valueOf(valore2));
gives:
5
5
in the console.
This is a follow on from my previous question which can be found here
Link For Previous Question
I am posting a new question as the answer I got was correct, however my next question is how to take it a step further
Basically I have a string of data, within this data somewhere there will be the following;
Width = 70
Void = 40
The actual numbers there could be anything between 1-440.
From my previous question I found how to identify those two digits using regular expression and put them into separate fields, however, my issue now is that the string could contain for example
Part Number = 2353
Length = 3.3mm
Width = 70
Void = 35
Discount = 40%
My question is;
How do I identify only the Width + Void and put them into two separate fields, the answer in my previous question would not solve this issue as what would happen is in this example I would have an array of size 4 and I would simply select the 2nd and 3rd space.
This is not suitable for my issue as the length of array could vary from string to string therefore I need a way of identifying specifically
Width = ##
Void = ##
And from there be able to retrieve the digits individually to put into my separate fields
I am using JavaScript in CRM Dynamics
A simpler option is to convert the whole string into an object and get what you need from that object.
str = "Part Number = 2353\n" +
"Length = 3.3mm\n" +
"Width = 70\n" +
"Void = 35\n" +
"Discount = 40%\n";
data = {};
str.replace(/^(.+?)\s*=\s*(.+)$/gm, function(_, $1, $2) {
data[$1] = $2;
});
alert(data['Width']);
Width\s+=\s+(\d+)|Void\s+=\s+(\d+)
You can try this.Grab the capture.See demo.
http://regex101.com/r/oE6jJ1/31
var re = /Width\s+=\s+(\d+)|Void\s+=\s+(\d+)/igm;
var str = 'Part Number = 2353\n\nLength = 3.3mm\n\nWidth = 70\n\nVoid = 35\n\nDiscount = 40%';
var m;
while ((m = re.exec(str)) != null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
// View your result using the m-variable.
// eg m[0] etc.
}
You can use this regex for matching input with Width and Void in any order:
/(\b(Width|Void) += *(\d+)\b)/
RegEx Demo
Your variable names and values are available in captured groups.
I'm getting the following error in my app's script when replacing strings in a template file to generate reports.
Index (-1) value must be greater or equal to zero.
The function is listed bellow.
/**
* Search a String in the document and replaces it with the generated newString, and sets it Bold
*/
function replaceString(doc, String, newString) {
var ps = doc.getParagraphs();
for(var i=0; i<ps.length; i++) {
var p = ps[i];
var text = p.getText();
//var text = p.editAsText();
if(text.indexOf(String) >= 0) {
//look if the String is present in the current paragraph
//p.editAsText().setFontFamily(b, c, DocumentApp.FontFamily.COMIC_SANS_MS);
p.editAsText().replaceText(String, newString);
// we calculte the length of the string to modify, making sure that is trated like a string and not another ind of object.
var newStringLength = newString.toString().length;
// if a string has been replaced with a NON empty space, it sets the new string to Bold,
Logger.log([newString,newStringLength]);
if (newStringLength > 0) {
// re-populate the text variable with the updated content of the paragraph
text = p.getText();
Logger.log(text);
p.editAsText().setBold(text.indexOf(newString), text.indexOf(newString) + newStringLength - 1, true);
}
}
}
}
When it errors out
[newString,newStringLength] = [ The Rev Levels are at ZGS 003 on the electric quality standard. The part has a current change to ZGS 005!,108]
Does anyone have any suggestions?
Thanks in advance,
Michael
You are not handling the case where the string isnt there. Thus indexOf returns -1 and you use that. Also dont use reserved words like String for variable names.
For example, if you have an expression like this:
Expression<Func<int, int>> fn = x => x * x;
Is there anything that will traverse the expression tree and generate this?
"function(x) { return x * x; }"
It's probably not easy, but yes, it's absolutely feasible. ORMs like Entity Framework or Linq to SQL do it to translate Linq queries into SQL, but you can actually generate anything you want from the expression tree...
You should implement an ExpressionVisitor to analyse and transform the expression.
EDIT: here's a very basic implementation that works for your example:
Expression<Func<int, int>> fn = x => x * x;
var visitor = new JsExpressionVisitor();
visitor.Visit(fn);
Console.WriteLine(visitor.JavaScriptCode);
...
class JsExpressionVisitor : ExpressionVisitor
{
private readonly StringBuilder _builder;
public JsExpressionVisitor()
{
_builder = new StringBuilder();
}
public string JavaScriptCode
{
get { return _builder.ToString(); }
}
public override Expression Visit(Expression node)
{
_builder.Clear();
return base.Visit(node);
}
protected override Expression VisitParameter(ParameterExpression node)
{
_builder.Append(node.Name);
base.VisitParameter(node);
return node;
}
protected override Expression VisitBinary(BinaryExpression node)
{
base.Visit(node.Left);
_builder.Append(GetOperator(node.NodeType));
base.Visit(node.Right);
return node;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
_builder.Append("function(");
for (int i = 0; i < node.Parameters.Count; i++)
{
if (i > 0)
_builder.Append(", ");
_builder.Append(node.Parameters[i].Name);
}
_builder.Append(") {");
if (node.Body.Type != typeof(void))
{
_builder.Append("return ");
}
base.Visit(node.Body);
_builder.Append("; }");
return node;
}
private static string GetOperator(ExpressionType nodeType)
{
switch (nodeType)
{
case ExpressionType.Add:
return " + ";
case ExpressionType.Multiply:
return " * ";
case ExpressionType.Subtract:
return " - ";
case ExpressionType.Divide:
return " / ";
case ExpressionType.Assign:
return " = ";
case ExpressionType.Equal:
return " == ";
case ExpressionType.NotEqual:
return " != ";
// TODO: Add other operators...
}
throw new NotImplementedException("Operator not implemented");
}
}
It only handles lambdas with a single instruction, but anyway the C# compiler can't generate an expression tree for a block lambda.
There's still a lot of work to do of course, this is a very minimal implementation... you probably need to add method calls (VisitMethodCall), property and field access (VisitMember), etc.
Script# is used by Microsoft internal developers to do exactly this.
Take a look at Lambda2Js, a library created by Miguel Angelo for this exact purpose.
It adds a CompileToJavascript extension method to any Expression.
Example 1:
Expression<Func<MyClass, object>> expr = x => x.PhonesByName["Miguel"].DDD == 32 | x.Phones.Length != 1;
var js = expr.CompileToJavascript();
Assert.AreEqual("PhonesByName[\"Miguel\"].DDD==32|Phones.length!=1", js);
Example 2:
Expression<Func<MyClass, object>> expr = x => x.Phones.FirstOrDefault(p => p.DDD > 10);
var js = expr.CompileToJavascript();
Assert.AreEqual("System.Linq.Enumerable.FirstOrDefault(Phones,function(p){return p.DDD>10;})", js);
More examples here.
The expression has already been parsed for you by the C# compiler; all that remains is for you to traverse the expression tree and generate the code. Traversing the tree can be done recursively, and each node could be handled by checking what type it is (there are several subclasses of Expression, representing e.g. functions, operators, and member lookup). The handler for each type can generate the appropriate code and traverse the node's children (which will be available in different properties depending on which expression type it is). For instance, a function node could be processed by first outputting "function(" followed by the parameter name followed by ") {". Then, the body could be processed recursively, and finally, you output "}".
A few people have developed open source libraries seeking to solve this problem. The one I have been looking at is Linq2CodeDom, which converts expressions into a CodeDom graph, which can then be compiled to JavaScript as long as the code is compatible.
Script# leverages the original C# source code and the compiled assembly, not an expression tree.
I made some minor edits to Linq2CodeDom to add JScript as a supported language--essentially just adding a reference to Microsoft.JScript, updating an enum, and adding one more case in GenerateCode. Here is the code to convert an expression:
var c = new CodeDomGenerator();
c.AddNamespace("Example")
.AddClass("Container")
.AddMethod(
MemberAttributes.Public | MemberAttributes.Static,
(int x) => "Square",
Emit.#return<int, int>(x => x * x)
);
Console.WriteLine(c.GenerateCode(CodeDomGenerator.Language.JScript));
And here is the result:
package Example
{
public class Container
{
public static function Square(x : int)
{
return (x * x);
}
}
}
The method signature reflects the more strongly-typed nature of JScript. It may be better to use Linq2CodeDom to generate C# and then pass this to Script# to convert this to JavaScript. I believe the first answer is the most correct, but as you can see by reviewing the Linq2CodeDom source, there is a lot of effort involved on handling every case to generate the code correctly.