Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for extractexcel.cs

(view source code of extractexcel.cs as plain text)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Text;
  9. using System.Text.RegularExpressions;
  10. using System.Threading;
  11. using mXparser = org.mariuszgromada.math.mxparser;
  12. using Excel = Microsoft.Office.Interop.Excel;
  13.  
  14.  
  15. namespace RobvanderWoude
  16. {
  17.     class ExtractExcel
  18.     {
  19. 		#region Global Variables
  20.  
  21. 		static readonly string progver = "1.00";
  22.  
  23. 		static bool closewithoutprompt = false;
  24. 		static Excel.Application excelApp;
  25. 		static readonly object readOnly = true;
  26. 		static readonly object missing = Missing.Value;
  27. 		static readonly object noSaveChanges = false;
  28. 		static readonly object saveChanges = true;
  29. 		static Excel.Workbook workbookSource;
  30. 		static Excel.Worksheet workseetSource;
  31. 		static Excel.Workbook workbookTarget;
  32. 		static Excel.Worksheet worksheetTarget;
  33. 		static string sourcefile = string.Empty;
  34. 		static string sourcesheet = string.Empty;
  35. 		static string targetfile = string.Empty;
  36. 		static string targetsheet = string.Empty;
  37. 		static int startrowtarget = 1;
  38. 		static List<int> rows = new List<int>( );
  39. 		static List<string> columns = new List<string>( );
  40. 		static string query = string.Empty;
  41. 		static readonly string parentfolder = Path.GetDirectoryName( new System.Uri( System.Reflection.Assembly.GetExecutingAssembly( ).CodeBase ).LocalPath );
  42.  
  43. 		#endregion Global Variables
  44.  
  45.  
  46. 		static int Main(string[] args)
  47.         {
  48.             int rc = 0;
  49.  
  50.  
  51. 			#region mXparser License Requirements
  52.  
  53. 			mXparser.License.iConfirmNonCommercialUse( "Rob van der Woude" );
  54. 			string resource = "ExtractExcel.MathParser.org-mXparser.LICENSE.txt";
  55. 			string readme = "MathParser.org-mXparser.LICENSE.txt";
  56. 			if ( !File.Exists( Path.Combine( parentfolder, resource ) ) )
  57. 			{
  58. 				ExtractEmbeddedResource( resource, readme );
  59. 			}
  60.  
  61. 			#endregion mXparser License Requirements
  62.  
  63.  
  64. 			#region Parse Command Line
  65.  
  66. 			if ( args.Length < 6 || args.Contains( "/?" ) )
  67.             {
  68.                 return ShowHelp( );
  69.             }
  70.  
  71.             for ( int i = 0; i < args.Length - 1; i++ )
  72.             {
  73.                 switch (args[i].ToUpper( ) )
  74.                 {
  75. 					case "/SOURCE":
  76. 						sourcefile = args[i + 1];
  77. 						if ( args.Length > i + 1 && args[i + 2][0] != '/' )
  78. 						{
  79. 							sourcesheet = args[i + 2];
  80. 						}
  81. 						break;
  82. 					case "/TARGET":
  83. 						targetfile = args[i + 1];
  84. 						if ( args[i + 2][0] != '/' )
  85. 						{
  86. 							targetsheet = args[i + 2];
  87. 						}
  88. 						break;
  89. 					case "/ROWS":
  90. 						rows = Range2Rows( args[i + 1] );
  91.                         break;
  92.                     case "/COLS":
  93.                     case "/COLUMNS":
  94. 						columns = Range2Columns( args[i + 1] );
  95.                         break;
  96. 					case "/OFFSET":
  97. 						startrowtarget = int.Parse( args[i + 1] );
  98. 						break;
  99.                     case "/WHERE":
  100. 						query = args[i + 1];
  101.                         break;
  102. 				}
  103. 			}
  104.  
  105. 			if ( columns.Count == 0 )
  106. 			{
  107. 				if ( rows.Count == 0 )
  108. 				{
  109. 					return ShowHelp( "Specify rows or columns or both" );
  110. 				}
  111. 				else
  112. 				{
  113. 					columns = Range2Columns( "A..Z" );
  114. 				}
  115. 			}
  116.  
  117. 			if ( rows.Count == 0 )
  118. 			{
  119. 				rows = Range2Rows( "1..100" );
  120. 			}
  121.  
  122. 			#endregion Parse Command Line
  123.  
  124.  
  125. 			// Make sure Excel is not active
  126. 			KillExcelIfActive( );
  127.  
  128. 			excelApp = new Excel.Application( );
  129.  
  130.  
  131. 			#region Prepare Excel Source and Target Files
  132.  
  133. 			if ( IsOpened( sourcefile, excelApp ) )
  134. 			{
  135. 				Console.Error.WriteLine( "Excel file \"{0}\" in use.\nPlease close it and try again.", sourcefile );
  136. 				return -1;
  137. 			}
  138.  
  139. 			excelApp.Visible = true;
  140. 			workbookSource = excelApp.Workbooks.Open( sourcefile, 0, readOnly, missing, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false );
  141. 			if ( string.IsNullOrEmpty( sourcesheet ) )
  142. 			{
  143. 				workseetSource = (Excel.Worksheet)workbookSource.Worksheets[1];
  144. 			}
  145. 			else if ( int.TryParse( sourcesheet, out int sheetindex ) )
  146. 			{
  147. 				workseetSource = (Excel.Worksheet)workbookSource.Worksheets[sheetindex];
  148. 			}
  149. 			else
  150. 			{
  151. 				workseetSource = (Excel.Worksheet)workbookSource.Worksheets[sourcesheet];
  152. 			}
  153. 			workseetSource = (Excel.Worksheet)workbookSource.ActiveSheet;
  154.  
  155. 			if ( File.Exists( targetfile ) )
  156. 			{
  157. 				if ( IsOpened( targetfile, excelApp ) )
  158. 				{
  159. 					Console.Error.WriteLine( "Excel file \"{0}\" in use.\nPlease close it and try again.", targetfile );
  160. 					return -1;
  161. 				}
  162. 				workbookTarget = excelApp.Workbooks.Open( targetfile, 0, readOnly, missing, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false );
  163. 			}
  164. 			else
  165. 			{
  166. 				// Create target file
  167. 				workbookTarget = excelApp.Workbooks.Add( );
  168. 				workbookTarget.SaveAs( targetfile );
  169. 				targetsheet = string.Empty;
  170. 			}
  171.  
  172. 			if ( string.IsNullOrEmpty( targetsheet ) )
  173. 			{
  174. 				worksheetTarget = (Excel.Worksheet)workbookTarget.Worksheets[1];
  175. 			}
  176. 			else if ( int.TryParse( targetsheet, out int sheetindex ) )
  177. 			{
  178. 				worksheetTarget = (Excel.Worksheet)workbookTarget.Worksheets[sheetindex];
  179. 			}
  180. 			else
  181. 			{
  182. 				worksheetTarget = (Excel.Worksheet)workbookTarget.Worksheets[targetsheet];
  183. 			}
  184. 			worksheetTarget = (Excel.Worksheet)workbookTarget.ActiveSheet;
  185.  
  186. 			#endregion Prepare Excel Source and Target Files
  187.  
  188.  
  189. 			try
  190. 			{
  191. 				int targetrow = startrowtarget;
  192. 				foreach ( int sourcerow in rows )
  193. 				{
  194. 					if ( CopyExcelRow( sourcerow, targetrow ) )
  195. 					{
  196. 						targetrow++;
  197. 					}
  198. 					else
  199. 					{
  200. 						rc = -1;
  201. 					}
  202. 				}
  203. 			}
  204. 			catch ( Exception ex )
  205. 			{
  206. 				Console.Error.WriteLine( "Error: {0}\n{1}", ex.Message, ex.StackTrace );
  207. 				rc = -1;
  208. 			}
  209. 			finally
  210. 			{
  211. 				if ( !ShutdownExcel( ) )
  212. 				{
  213. 					rc = -1;
  214. 				}
  215. 			}
  216.  
  217. 			return rc;
  218.         }
  219.  
  220.  
  221. 		static bool CopyExcelRow( int sourcerow, int targetrow )
  222. 		{
  223. 			bool success = true;
  224.  
  225. 			if ( !string.IsNullOrWhiteSpace( query ) )
  226. 			{
  227. 				// Replace cell name with cell value
  228. 				// based on code by Vladimir
  229. 				// https://stackoverflow.com/a/62778031
  230. 				string currentquery = query;
  231. 				string pattern = @"\b([A-Z]+)\b";
  232. 				RegexOptions options = RegexOptions.None; // case sensitive
  233. 				Match match;
  234. 				while ( ( match = Regex.Match( currentquery, pattern, options ) ).Success )
  235. 				{
  236. 					var group = match.Groups[1];
  237. 					var sb = new StringBuilder( );
  238. 					// Anything before the match
  239. 					if ( match.Index > 0 )
  240. 					{
  241. 						sb.Append( currentquery.Substring( 0, match.Index ) );
  242. 					}
  243. 					// The match itself
  244. 					var startIndex = group.Index - match.Index;
  245. 					var length = group.Length;
  246. 					var original = match.Value;
  247. 					var prior = original.Substring( 0, startIndex );
  248. 					var trailing = original.Substring( startIndex + length );
  249. 					sb.Append( prior );
  250. 					object cellvalue = ReadCell( workseetSource, sourcerow, group.Value );
  251. 					if ( cellvalue == null )
  252. 					{
  253. 						return false;
  254. 					}
  255. 					if ( cellvalue.GetType( ) == typeof( Single ) || cellvalue.GetType( ) == typeof( Double ) )
  256. 					{
  257. 						sb.Append( FormatFloat( cellvalue ) );
  258. 					}
  259. 					else
  260. 					{
  261. 						sb.Append( cellvalue );
  262. 					}
  263. 					sb.Append( trailing );
  264. 					// Anything after the match
  265. 					if ( match.Index + match.Length < currentquery.Length )
  266. 					{
  267. 						sb.Append( currentquery.Substring( match.Index + match.Length ) );
  268. 					}
  269. 					currentquery = sb.ToString( );
  270. 				}
  271.  
  272. 				org.mariuszgromada.math.mxparser.Expression expression = new org.mariuszgromada.math.mxparser.Expression( currentquery );
  273. 				if ( !expression.checkSyntax( ) )
  274. 				{
  275. 					return false;
  276. 				}
  277.  
  278. 				bool valid = ( expression.calculate( ) == 1.0 );
  279.  
  280. 				if ( valid )
  281. 				{
  282. 					int targetcolumn = 1;
  283. 					foreach ( string sourcecolumn in columns )
  284. 					{
  285. 						object cellValue = ReadCell( workseetSource, sourcerow, sourcecolumn );
  286. 						if ( !WriteCell( worksheetTarget, targetrow, targetcolumn, cellValue ) )
  287. 						{
  288. 							success = false;
  289. 						}
  290. 						targetcolumn++;
  291. 					}
  292. 				}
  293. 			}
  294. 			return success;
  295. 		}
  296.  
  297.  
  298. 		static bool Empty( object value )
  299. 		{
  300. 			if ( value == null )
  301. 			{
  302. 				return true;
  303. 			}
  304. 			if ( string.IsNullOrEmpty( value.ToString( ) ) )
  305. 			{
  306. 				return true;
  307. 			}
  308. 			return false;
  309. 		}
  310.  
  311.  
  312. 		static void ExtractEmbeddedResource( string resourcename, string filename = null )
  313. 		{
  314. 			var embeddedResource = Assembly.GetExecutingAssembly( ).GetManifestResourceNames( ).FirstOrDefault( s => string.Compare( s, resourcename, true ) == 0 );
  315. 			if ( string.IsNullOrWhiteSpace( filename ) )
  316. 			{
  317. 				filename = resourcename;
  318. 			}
  319. 			// Ensure that the file is in the program's parent folder
  320. 			filename = Path.Combine( parentfolder, Path.GetFileName( filename ) );
  321. 			resourcename = "ExtractExcel." + resourcename;
  322. 			Stream stream = Assembly.GetExecutingAssembly( ).GetManifestResourceStream( embeddedResource );
  323. 			byte[] bytes = new byte[(int)stream.Length];
  324. 			stream.Read( bytes, 0, bytes.Length );
  325. 			stream.Close( );
  326. 			File.WriteAllBytes( filename, bytes );
  327. 		}
  328.  
  329.  
  330. 		static string FormatFloat( Double val )
  331. 		{
  332. 			return val.ToString( new CultureInfo( "en-US" ) );
  333. 		}
  334.  
  335.  
  336. 		static string FormatFloat( object val )
  337. 		{
  338. 			return ( (Double)val ).ToString( new CultureInfo( "en-US" ) );
  339. 		}
  340.  
  341.  
  342. 		static string FormatFloat( Single val )
  343. 		{
  344. 			return val.ToString( new CultureInfo( "en-US" ) );
  345. 		}
  346.  
  347.  
  348. 		static bool InRange( char col, string colrange )
  349. 		{
  350. 			return InRange( col.ToString( ), colrange );
  351. 		}
  352.  
  353.  
  354. 		static bool InRange( string col, string colrange )
  355. 		{
  356. 			List<string> columns = Range2Columns( colrange );
  357. 			if ( columns.Contains( col.ToUpper( ) ) )
  358. 			{
  359. 				return true;
  360. 			}
  361. 			return false;
  362. 		}
  363.  
  364.  
  365. 		static bool InRange( int col, string colrange )
  366. 		{
  367. 			List<string> columns = Range2Columns( colrange );
  368. 			if ( columns.Contains( col.ToString( ) ) )
  369. 			{
  370. 				return true;
  371. 			}
  372. 			if ( columns.Contains( ( (char)( col + 64 ) ).ToString( ) ) )
  373. 			{
  374. 				return true;
  375. 			}
  376. 			return false;
  377. 		}
  378.  
  379.  
  380. 		static bool InRange( int col, int[] colrange )
  381. 		{
  382. 			return ( colrange.Contains( col ) );
  383. 		}
  384.  
  385.  
  386. 		static bool IsOpened( string excelfile, Excel.Application xlAppRef )
  387. 		{
  388. 			bool isOpened = true;
  389. 			try
  390. 			{
  391. 				// wbook should be: "name-of-the-workbook.xlsx". Otherwise it will always raise the
  392. 				// exception and never return true
  393. 				var test = xlAppRef.Workbooks.Item[Path.GetFileName( excelfile )];
  394.  
  395. 			}
  396. 			catch ( Exception )
  397. 			{
  398. 				isOpened = false;
  399. 			}
  400. 			return isOpened;
  401. 		}
  402.  
  403.  
  404. 		static bool IsActive( string progname )
  405. 		{
  406. 			using ( Process prog = Process.GetProcessesByName( progname ).FirstOrDefault( ) )
  407. 			{
  408. 				return ( prog != null );
  409. 			}
  410. 		}
  411.  
  412.  
  413. 		static void KillExcel( )
  414. 		{
  415. 			try
  416. 			{
  417. 				foreach ( Process proc in Process.GetProcessesByName( "excel" ) )
  418. 				{
  419. 					proc.Kill( );
  420. 				}
  421. 			}
  422. 			catch
  423. 			{
  424. 				// ignore
  425. 			}
  426. 		}
  427.  
  428.  
  429. 		static void KillExcelIfActive( )
  430. 		{
  431. 			bool excelactive = IsActive( "excel" );
  432. 			if ( excelactive )
  433. 			{
  434. 				if ( closewithoutprompt )
  435. 				{
  436. 					KillExcel( );
  437. 				}
  438. 				else
  439. 				{
  440. 					Thread.Sleep( 1000 );
  441. 					if ( !IsActive( "excel" ) )
  442. 					{
  443. 						return;
  444. 					}
  445. 					string message;
  446. 					message = "Excel is still active.\nClose it before continuing.\n\n";
  447. 					message += "Press Enter when Excel is closed, or Escape to abort.";
  448. 					Console.WriteLine( message );
  449. 					bool validkey = false;
  450. 					while ( !validkey )
  451. 					{
  452. 						ConsoleKey answer = Console.ReadKey( true ).Key;
  453. 						if ( answer == ConsoleKey.Enter )
  454. 						{
  455. 							closewithoutprompt = true;
  456. 							KillExcel( );
  457. 							validkey = true;
  458. 						}
  459. 						else if ( answer == ConsoleKey.Escape )
  460. 						{
  461. 							Environment.Exit( -1 );
  462. 							validkey = true;
  463. 						}
  464. 					}
  465. 				}
  466. 			}
  467. 		}
  468.  
  469.  
  470. 		static List<int> Range2Rows( string range )
  471. 		{
  472. 			List<int> rows = new List<int>( );
  473. 			foreach ( string part in range.Split( ',' ) )
  474. 			{
  475. 				if ( part.Contains( ".." ) )
  476. 				{
  477. 					char[] separator = ".".ToCharArray( );
  478. 					StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries;
  479. 					int startrange = int.Parse( part.Split( separator, options )[0] );
  480. 					int endrange = int.Parse( part.Split( separator, options )[1] );
  481. 					for ( int i = (int)startrange; i <= (int)endrange; i++ )
  482. 					{
  483. 						rows.Add( i );
  484. 					}
  485. 				}
  486. 				else
  487. 				{
  488. 					rows.Add( int.Parse( part ) );
  489. 				}
  490. 			}
  491. 			return rows;
  492. 		}
  493.  
  494.  
  495. 		static List<string> Range2Columns( string range )
  496. 		{
  497. 			List<string> columns = new List<string>( );
  498. 			foreach ( string part in range.Split( ',' ) )
  499. 			{
  500. 				if ( part.Contains( ".." ) )
  501. 				{
  502. 					char startrange = part[0];
  503. 					char endrange = part[part.Length - 1];
  504. 					for ( int i = (int)startrange; i <= (int)endrange; i++ )
  505. 					{
  506. 						columns.Add( ( (char)i ).ToString( ).ToUpper( ) );
  507. 					}
  508. 				}
  509. 				else
  510. 				{
  511. 					columns.Add( part.ToUpper( ) );
  512. 				}
  513. 			}
  514. 			return columns;
  515. 		}
  516.  
  517.  
  518. 		static object ReadCell( Excel.Worksheet worksheet, int row, string col )
  519. 		{
  520. 			int colnum = Convert.ToInt32( col.ToUpper( )[0] ) - 64;
  521. 			Excel.Range cell = (Excel.Range)worksheet.Range[worksheet.Cells[row, colnum], worksheet.Cells[row, colnum]];
  522. 			return cell.Value;
  523. 		}
  524.  
  525.  
  526. 		static object ReadCell( Excel.Worksheet worksheet, int row, int col )
  527. 		{
  528. 			Excel.Range cell = (Excel.Range)worksheet.Range[worksheet.Cells[row, col], worksheet.Cells[row, col]];
  529. 			return cell.Value;
  530. 		}
  531.  
  532.  
  533. 		static int ShowHelp( params string[] errmsg )
  534. 		{
  535. 			#region Error Message
  536.  
  537. 			if ( errmsg.Length > 0 )
  538. 			{
  539. 				List<string> errargs = new List<string>( errmsg );
  540. 				errargs.RemoveAt( 0 );
  541. 				Console.Error.WriteLine( );
  542. 				Console.ForegroundColor = ConsoleColor.Red;
  543. 				Console.Error.Write( "ERROR:\t" );
  544. 				Console.ForegroundColor = ConsoleColor.White;
  545. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  546. 				Console.ResetColor( );
  547. 			}
  548.  
  549. 			#endregion Error Message
  550.  
  551.  
  552. 			#region Help Text
  553.  
  554. 			/*
  555. 			ExtractExcel,  Version 1.00
  556. 			Filter values from a source spreadsheet and write them to a target spreadsheet
  557.  
  558. 			Usage:   ExtractExcel /SOURCE src /TARGET tgt /COLS "cols" [ options ]
  559.  
  560. 			Where:   src      is the source file name and optional sheet name or index
  561. 			                  (e.g. source.xlsx "Sheet 2"; default sheet index 1)
  562. 			         tgt      is the target file name and optional sheet name or index
  563. 			                  (e.g. target.xlsx 3; default sheet index 1; file is created
  564. 			                  if it does not exist, in which case sheet will be ignored)
  565. 			         cols     is a list or range of columns to be read from the source file
  566. 			                  (letters, e.g. "A..D,F,AA..AG", case insensitive, mandatory
  567. 			                  unless rows are specified, default if rows specified: "A..Z")
  568.  
  569. 			Options: /ROWS    rows      list or range of rows to be used from source file
  570. 			                            (numeric, e.g. "1,3,5..8,14", default: "1..100")
  571. 			         /OFFSET  startrow  first row in target sheet to be written
  572. 			                            (numeric, default: 1)
  573. 			         /WHERE   query     filter rule, source row will be skipped if it does
  574. 			                            not comply (see notes; default: do not skip)
  575.  
  576. 			Notes:   Queries format is "column operator value/column", e.g. "A < 0", "B > C"
  577. 			         or "AF != 1.5"; whitespace is allowed; columns must be in upper case!
  578. 			         Queries are interpreted by mXparser (https://mathparser.org/)
  579. 			         See its tutorial at https://mathparser.org/mxparser-tutorial/ for
  580. 			         details on more complex filter expressions, e.g. "(A=10)|(B<0)".
  581. 			         Return code ("errorlevel") -1 in case of errors, otherwise 0.
  582.  
  583. 			Credits: Code to replace column by cell value by Vladimir
  584. 			         https://stackoverflow.com/a/62778031
  585. 			         Query parsing by mXparser
  586. 			         https://mathparser.org/
  587. 			         Manipulating Excel files by Microsoft.Office.Interop.Excel
  588. 			         https://www.nuget.org/packages/Microsoft.Office.Interop.Excel
  589.  
  590. 			Written by Rob van der Woude
  591. 			https://www.robvanderwoude.com
  592. 			*/
  593.  
  594. 			#endregion Help Text
  595.  
  596.  
  597. 			#region Display Help Text
  598.  
  599. 			Console.Error.WriteLine( );
  600.  
  601. 			Console.Error.WriteLine( "ExtractExcel,  Version {0}", progver );
  602.  
  603. 			Console.Error.WriteLine( "Filter values from a source spreadsheet and write them to a target spreadsheet" );
  604.  
  605. 			Console.Error.WriteLine( );
  606.  
  607. 			Console.Error.Write( "Usage:   " );
  608. 			Console.ForegroundColor = ConsoleColor.White;
  609. 			Console.Error.WriteLine( "ExtractExcel /SOURCE src /TARGET tgt /COLS \"cols\" [ options ]" );
  610. 			Console.ResetColor( );
  611.  
  612. 			Console.Error.WriteLine( );
  613.  
  614. 			Console.Error.Write( "Where:   " );
  615. 			Console.ForegroundColor = ConsoleColor.White;
  616. 			Console.Error.Write( "src" );
  617. 			Console.ResetColor( );
  618. 			Console.Error.WriteLine( "      is the source file name and optional sheet name or index" );
  619.  
  620. 			Console.Error.WriteLine( "                  (e.g. source.xlsx \"Sheet 2\"; default sheet index 1)" );
  621.  
  622. 			Console.ForegroundColor = ConsoleColor.White;
  623. 			Console.Error.Write( "         tgt" );
  624. 			Console.ResetColor( );
  625. 			Console.Error.WriteLine( "      is the target file name and optional sheet name or index" );
  626.  
  627. 			Console.Error.WriteLine( "                  (e.g. target.xlsx 3; default sheet index 1; file is created" );
  628.  
  629. 			Console.Error.WriteLine( "                  if it does not exist, in which case sheet will be ignored)" );
  630.  
  631. 			Console.ForegroundColor = ConsoleColor.White;
  632. 			Console.Error.Write( "         cols" );
  633. 			Console.ResetColor( );
  634. 			Console.Error.WriteLine( "     is a list or range of columns to be read from the source file" );
  635.  
  636. 			Console.Error.WriteLine( "                  (letters, e.g. \"A..D,F,AA..AG\", case insensitive, mandatory" );
  637.  
  638. 			Console.Error.WriteLine( "                  unless rows are specified, default if rows specified: \"A..Z\")" );
  639.  
  640. 			Console.Error.WriteLine( );
  641.  
  642. 			Console.Error.Write( "Options: " );
  643. 			Console.ForegroundColor = ConsoleColor.White;
  644. 			Console.Error.Write( "/ROWS    rows" );
  645. 			Console.ResetColor( );
  646. 			Console.Error.WriteLine( "      list or range of rows to be used from source file" );
  647.  
  648. 			Console.Error.WriteLine( "                            (numeric, e.g. \"1,3,5..8,14\", default: \"1..100\")" );
  649.  
  650. 			Console.Error.WriteLine( );
  651.  
  652. 			Console.ForegroundColor = ConsoleColor.White;
  653. 			Console.Error.Write( "         /OFFSET  startrow" );
  654. 			Console.ResetColor( );
  655. 			Console.Error.WriteLine( "  first row in target sheet to be written" );
  656.  
  657. 			Console.Error.WriteLine( "                            (numeric, default: 1)" );
  658.  
  659. 			Console.ForegroundColor = ConsoleColor.White;
  660. 			Console.Error.Write( "         /WHERE   query" );
  661. 			Console.ResetColor( );
  662. 			Console.Error.WriteLine( "     filter rule, source row will be skipped if it does" );
  663.  
  664. 			Console.Error.WriteLine( "                            not comply (see notes; default: do not skip)" );
  665.  
  666. 			Console.Error.WriteLine( );
  667.  
  668. 			Console.Error.WriteLine( "Notes:   Queries format is \"column operator value/column\", e.g. \"A < 0\", \"B > C\"" );
  669.  
  670. 			Console.Error.WriteLine( "         or \"AF != 1.5\"; whitespace is allowed; columns must be in upper case!" );
  671.  
  672. 			Console.Error.Write( "         Queries are interpreted by mXparser (" );
  673. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  674. 			Console.Error.Write( "https://mathparser.org/" );
  675. 			Console.ResetColor( );
  676. 			Console.Error.WriteLine( ")" );
  677.  
  678. 			Console.Error.Write( "         See its tutorial at " );
  679. 			Console.ForegroundColor= ConsoleColor.DarkGray;
  680. 			Console.Error.Write( "https://mathparser.org/mxparser-tutorial/" );
  681. 			Console.ResetColor( );
  682. 			Console.Error.WriteLine( " for" );
  683.  
  684. 			Console.Error.WriteLine( "         details on more complex filter expressions, e.g. \"(A=10)|(B<0)\"." );
  685.  
  686. 			Console.Error.WriteLine( "         Return code (\"errorlevel\") -1 in case of errors, otherwise 0." );
  687.  
  688. 			Console.Error.WriteLine( );
  689.  
  690. 			Console.Error.WriteLine( "Credits: Code to replace column by cell value by Vladimir" );
  691.  
  692. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  693. 			Console.Error.WriteLine( "         https://stackoverflow.com/a/62778031" );
  694. 			Console.ResetColor( );
  695.  
  696.  
  697.  
  698. 			Console.Error.WriteLine( "         Query parsing by mXparser" );
  699.  
  700. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  701. 			Console.Error.WriteLine( "         https://mathparser.org/" );
  702. 			Console.ResetColor( );
  703.  
  704.  
  705.  
  706. 			Console.Error.WriteLine( "         Manipulating Excel files by Microsoft.Office.Interop.Excel" );
  707.  
  708. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  709. 			Console.Error.WriteLine( "         https://www.nuget.org/packages/Microsoft.Office.Interop.Excel" );
  710. 			Console.ResetColor( );
  711.  
  712.  
  713.  
  714. 			Console.Error.WriteLine( );
  715.  
  716. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  717.  
  718. 			Console.Error.WriteLine( "https://www.robvanderwoude.com" );
  719.  
  720. 			#endregion Display Help Text
  721.  
  722.  
  723. 			return -1;
  724. 		}
  725.  
  726.  
  727. 		static bool ShutdownExcel( )
  728. 		{
  729. 			try
  730. 			{
  731. 				workbookSource.Close( noSaveChanges );
  732. 				workbookTarget.Close( saveChanges );
  733. 				excelApp.Quit( );
  734. 				return true;
  735. 			}
  736. 			catch ( Exception ex )
  737. 			{
  738. 				Console.Error.WriteLine( "Foutmelding bij afluiten Excel: " + ex.Message );
  739. 				Console.Error.WriteLine( ex.StackTrace );
  740. 				return false;
  741. 			}
  742. 		}
  743.  
  744.  
  745. 		static bool WriteCell( Excel.Worksheet worksheet, int row, int col, object value )
  746. 		{
  747. 			Excel.Range cell = (Excel.Range)worksheet.Range[worksheet.Cells[row, col], worksheet.Cells[row, col]];
  748. 			cell.Value = value;
  749. 			object trueval = ReadCell( worksheet, row, col );
  750. 			if ( Empty( value ) )
  751. 			{
  752. 				return Empty( trueval );
  753. 			}
  754. 			if ( Empty( trueval ) )
  755. 			{
  756. 				return Empty( value );
  757. 			}
  758. 			return ( value.ToString( ) == trueval.ToString( ) );
  759. 		}
  760.  
  761. 	}
  762. }

page last modified: 2024-04-16; loaded in 0.0153 seconds